2009/6/22 Marco Di antonio [email protected]
sto sviluppando un gioco con RPG Maker VX che usa internalmente Ruby
1.8.1.
1.8.1… non è un po’ vetusta come versione?
Sto scrivendo uno script che avvia un processo, ad esempio notepad.exe
in modo da non bloccare il codice di esecuzione.
Parto dal presupposto che con “non bloccare il codice di esecuzione”
tu intenda che non appena notepad.exe viene lanciato, il controllo
torna allo script ruby in modo da poter proseguire con il normale
flusso dell’applicazione (cosa che di fatto esclude metodi come system
poiché “ascoltano” l’stdout del nuovo processo, bloccando di fatto lo
script ruby fino alla chiusura del processo stesso).
Detto questo, ci sarebbe win32-process che è comodissima come libreria
(richiede come dipendenza windows-pr), ma la compatibilità è data solo
da ruby 1.8.2 in poi e se effettivamente hai a disposizione solo
1.8.1…
Ad ogni modo ecco un esempio:
require ‘win32/process’
process_info = Process.create(
:app_name => “notepad.exe”,
:creation_flags => Process::DETACHED_PROCESS,
:process_inherit => false
)
Il problema principale è che non posso usare “require” perchè non lo
capisce.
Più che altro, require non c’entra con quanto vorresti ottenere.
Qualcuno ha un’idea di come posso fare?
Qualcosa tipo Win32API.new( ‘kernel32’, “CreateProcess”, [‘L’], “n” )
Più complesso (e molto più noioso) di win32-process, ma almeno non ti
porti dietro dipendenze esterne rispetto alla stdlib di ruby. Ecco un
esempio ridotto all’osso, anche nella valorizzazione dei parametri:
close_handle = Win32API.new(‘kernel32’, ‘CloseHandle’, ‘L’, ‘L’)
create_process = Win32API.new(‘kernel32’, ‘CreateProcess’, ‘PPPPLLLPPP’,
‘L’)
startup_info =
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0].pack(‘LLLLLLLLLLLLSSLLLL’)
process_info = [0,0,0,0].pack(‘LLLL’)
created = create_process.call(
0, # lpApplicationName
“notepad.exe”, # lpCommandLine
0, # lpProcessAttributes
0, # lpThreadAttributes
0, # bInheritHandles
0x08, # dwCreationFlags
0, # lpEnvironment
“C:/Temp/”, # lpCurrentDirectory
startup_info, # lpStartupInfo
process_info # lpProcessInformation
)
close_handle.call(process_info[0,4].unpack(‘L’).first)
close_handle.call(process_info[4,4].unpack(‘L’).first)
Nota bene: process_info è una struttura al cui interno vengono
memorizzati gli handle del processo appena creato e del thread
principale di quest’ultimo. Essi vanno necessariamente chiusi
(certo, a meno che non ti servano in giro per la tua
applicazione/script ruby, ma dubito), pena il rimanere allocati in
memoria anche alla chiusura del processo esterno: questo ti porterebbe
inesorabilmente a leak di memoria se la tua applicazione principale
dovesse rimanere aperta per tanto tempo lanciando spesso processi
esterni. Uomo avvisato…
Comunque per la valorizzazione dei parametri di CreateProcess e altre
info c’è CreateProcessA function (processthreadsapi.h) - Win32 apps | Microsoft Learn
PS: dato che non so che diavolo verrà fuori come impaginazione, i due
snippet sono anche qui win32-process.rb · GitHub
Ciao,
Daniele
–
Daniele A.
http://www.clorophilla.net/blog/
http://twitter.com/JoL1hAHN