From: Chris Morris Date: 2002-10-18T11:19:35+09:00 Subject: Re: async system call on Windows? > I am interested in learning from your Ruby code ... if it is available for > public consumption, that is. Sure - here you go. Thx to Phil Tomson for posting a version of his CreateProcess in the archives which helped unstick me (I'd been trying 'P' and empty string for nil pointers, which I've seen work, but didn't work with CreateProcess. He used 'L' and 0 for nil pointers, and it worked great) def async_system(command) # http://msdn.microsoft.com/library/en-us/vccore98/html/_crt__spawnv.2c_._wspa wnv.asp # this is working -- but frequently Segfaults ruby 1.6.6 mswin32 spawn = Win32API.new("crtdll", "_spawnvp", ['I', 'P', 'P'] ,'L') # need to try the third param as an 'L' and pass it 0, maybe segfault # will go away? res = spawn.Call(P_NOWAIT, command, '') if res == -1 Win32API.new("crtdll", "perror", ['P'], 'V').call('async_system') end res end # from WinBase.h in SDK # dwCreationFlag values NORMAL_PRIORITY_CLASS = 0x00000020 STARTUP_INFO_SIZE = 68 PROCESS_INFO_SIZE = 16 def create_process(command) # from WinBase.h in SDK # Passing nil for a pointer -- I've seen it work with a P type param and # an empty string ... here L with a 0 is the only way that works with # CreateProcess. (see FormatMessage in raise_last_win32_error for an # example of 'P' and '' that works) params = [ 'L', # IN LPCSTR lpApplicationName 'P', # IN LPSTR lpCommandLine 'L', # IN LPSECURITY_ATTRIBUTES lpProcessAttributes 'L', # IN LPSECURITY_ATTRIBUTES lpThreadAttributes 'L', # IN BOOL bInheritHandles 'L', # IN DWORD dwCreationFlags 'L', # IN LPVOID lpEnvironment 'L', # IN LPCSTR lpCurrentDirectory 'P', # IN LPSTARTUPINFOA lpStartupInfo 'P' # OUT LPPROCESS_INFORMATION lpProcessInformation ] returnValue = 'I' # BOOL startupInfo = [STARTUP_INFO_SIZE].pack('I') + ([0].pack('I') * (STARTUP_INFO_SIZE - 4)) processInfo = [0].pack('I') * PROCESS_INFO_SIZE createProcess = Win32API.new("kernel32", "CreateProcess", params, returnValue) if createProcess.call(0, command, 0, 0, 0, NORMAL_PRIORITY_CLASS, 0, 0, startupInfo, processInfo) == 0 raise_last_win_32_error end processInfo end ERROR_SUCCESS = 0x00 FORMAT_MESSAGE_FROM_SYSTEM = 0x1000 FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x2000 def raise_last_win_32_error errorCode = Win32API.new("kernel32", "GetLastError", [], 'L').call if errorCode != ERROR_SUCCESS params = [ 'L', # IN DWORD dwFlags, 'P', # IN LPCVOID lpSource, 'L', # IN DWORD dwMessageId, 'L', # IN DWORD dwLanguageId, 'P', # OUT LPSTR lpBuffer, 'L', # IN DWORD nSize, 'P', # IN va_list *Arguments ] formatMessage = Win32API.new("kernel32", "FormatMessage", params, 'L') msg = ' ' * 255 msgLength = formatMessage.call(FORMAT_MESSAGE_FROM_SYSTEM + FORMAT_MESSAGE_ARGUMENT_ARRAY, '', errorCode, 0, msg, 255, '') msg.gsub!("\\000", '') msg.strip! raise msg else raise 'GetLastError returned ERROR_SUCCESS' end end All this code is BSD license - full code is part of a misc windows utility unit you can find here: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/scrapware/scrapware/ruby/cl/u til/win.rb?rev=1.13&content-type=text/vnd.viewcvs-markup Chris