From: Shashank Date Date: 2002-10-21T06:31:50+09:00 Subject: Re: async system call on Windows? Thanks a lot ! "Chris Morris" wrote in message news:016701c2764c$68c61800$6401a8c0@3ComC... > > 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 > >