Newsgroup: it.comp.lang.delphi
Titolo: Gli Handle che non corrispondono

Salve a tutti, uso D5.
Da una mia applicazione ho la necessità di lanciare un programma solo una
volta, nel senso che, se l'utente tenta di rilanciarlo (magari premendo un
pulsante), viene fatta una ricerca per sapere se l'applicazione è ancora
attiva, se lo è non viene rilanciata.
La mia applicazione lancia il programma usando la funzione "ShellExecute",
che mi ritorna l'handle di questa. Quando l'utente tenta di lanciarla una
seconda volta, utilizzando la funzione "IsWindow" (passandogli come
parametro l'handle che ShellExecute mi ritorna), dovrei riuscire a sapere se
il programma è ancora attivo o magari è stato chiuso. Ma questo non avviene.
Nei miei vari tentativi ho utilizzando anche la funzione "CreateProcess" che
tramite la struttura "PROCESS_INFORMATION" mi ritorna comunque un handle non
valido. Non riuscendo più a capacitarmi, ho realizzato un semplice programma
che quando lo si lancia, mostra nella caption della form il proprio handle.
A questo punto lancio questo semplice programma dalla mia famosa
applicazione e andando per step vado a leggere l'handle che mi ritorna
"ShellExecute" e scopro che è differente. Ma allora mi chiedo che razza di
numero mi ritorna questa funzione?
Di sicuro sbaglio qualcosa io.
Grazie in anticipo a tutti quelli che mi potranno aiutare e mi scuso se mi
sono dilungato, ma ci ho sbattuto la testa 2 giorni interi.

Se ho capito, stai leggendo l'handle dell'applicazione o del processo o
della finestra.. ad ogni modo, non puoi usare nessuno di questi per
controllare che la tua app stia gia' girando, perche' sono degli
identificatori univoci, cioe' in un momento determinato non ci saranno due
applicazioni con lo stesso handle, o due processi, o qualsiasi altra cosa
che su windows richieda un handle (file, porte, thread, semafori ecc ecc
ecc)
Quindi l'handle non e' uno strumento per trovare applicazioni simili, ma per
identificarle univocamente.
Per fare quello che vuoi tu, ti consiglio intanto di leggere le faq, dove e'
scritto come si fa, altrimenti di guardare su 
www.torry.net
 per un
componente gia' pronto (eventualmente da studiare)
Ciao!                {MSX}
--
{MSX}  -  
http://msx.rules.it
Mantenitore delle FAQ di it.comp.lang.delphi,
reperibili qui: 
http://gpi.infomedia.it/abc/delphi/FaqDelphi.txt

Ciao,
lasciamo stare il sistema dell'handle.
Non è un bel sistema.
In teoria si può controllare se prima di avviare il programma ( cioè devi
fare un controllo all'interno del file di progetto ) esiste già un handle
riferito ad una finestra del programma. ( con una determinata classe che
dipende dal nome della finestra )
Ovviamente devi sperare che per pura iella non esista un programma che ha
una finestra che si chiama con lo stesso nome, altrimenti il controllo darà
esito positivo e il programma non si avvierà mai.
Un altro problema di questo sistema, si verifica durante la compilazione con
successivo avvio del programma.
In pratica il controllo che fai all'interno del progetto ti proebisce
l'avvio del programma sotto Delphi ( se è aperta la finestra su cui fai il
controllo ). Insomma una noia pazzesca.
Volendo puoi usare le funzioni AddAtom, GetAtom ecc ecc...
Quest'ultime funzionano, anche se ci sono sistemi migliori ma un po' più
complessi.
Ciao.
Antonio

Forse mi sono spiegato male, ma a me interessa proprio identificare se una
applicazione lanciata dal mio programma è ancora attiva. Per questo io
memorizzo il valore di ritorno di "ShellExecute" e lo utilizzo per capire se
l'applicazione lanciata è ancora attiva. Mo non funziona. "IsWindow" non la
vede.

Purtroppo sono costretto ad utilizzare l'handle, perchè l'applicazione
lanciata non è realizzata da me e l'unico data identificativo di questa è
appunto l'handle assegnatogli dal sistema.

 interi. 
esempio non completo:
(* globale *)
var
 lastProcess: Cardinal = INVALID_HANDLE_VALUE;
(* locale *)
var
 shExInfo: SHELLEXECUTEINFO;
 exitCode: Integer;
begin
 (* un processo è stato già lanciato *)
 if lastProcess <> INVALID_HANDLE_VALUE then begin
  (* è ancora attivo? *)
  if not GetExitCodeProcess(lastProcess, exitCode) then
   RaiseLastWin32Error();
  (* è ancora attivo *)
  if exitCode = STILL_ACTIVE then begin
   Result:= False; (* solo un esempio *)
   Exit;
  end;
  (* non più attivo: fai pulizia *)
  CloseHandle(lastProcess);
  lastProcess:= INVALID_HANDLE_VALUE;
 end;
 shExInfo.cbSize:= SizeOf(shExInfo);
 shExInfo.fMask:= SEE_MASK_NOCLOSEPROCESS; (* importante *)
 (* imposta altri parametri in shexinfo *)
 if not ShellExecuteEx(shExInfo) then
  RaiseLastWin32Error();
 launchedProcess = shExInfo.hProcess;
 Result:= True;
end;
-- 
 < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
     Don't stand, REACT!      version 0.0.19. C, C++ and ASM developers
                              and beta testers are welcome!

 appunto l'handle assegnatogli dal sistema.
scusami, mi sono sbagliato ad interpretare la tua domanda.
Non considerare ciò che ti ho detto che può valere solo per la tua
applicazione.
Ti saluto
P.S. Se ho qualche suggerimento da darti posto nuovamente
Ciao
Antonio

Ho provato e funziona... in parte. Ossia il comportamento č uguale a quello
che ottenevo utilizzando "CreateProcess" e l'handle che mi restituiva in
"hProcess", cioč quello di funzionare solo quando l'applicazione chiamante
era attiva. Se io la chiudo e poi la rilancio, lasciando attivo il programma
che avevo lanciato precedentemente,  questo non viene piů visto ottenendo
una seconda copia del programma.
In pratica quello che io cerco e non riesco a ricavare, č l'handle univoco
dell'applicazione (quello che si ottiene con "FindWindow") che č quello che
mi permette di testare l'esistenza dell'applicazione indipendentemente dal
progetto che la lancia. Io l'unico dato che ho č il nome e il path del file
da lanciare. A questo punto credo che non sia possibile ottenere quello che
cerco con cosě pochi dati.
Grazie comunque per l'interessamento

 cerco con così pochi dati.
Fai una enumerazione dei processi attivi (ricavi i PID), quindi in base
al PID risali al nome del file che corrisponde al processo e se trovi
quello che corrisponde al tuo tutto bene, altrimenti lo rilanci.
Saluti
Paolo Arosio
// esempio adattato dalle JCL 
http://www.delphi-jedi.org/
sotto NT: uses psApi;
function FindProcessIDFromName(ProcName: string; var PID: DWORD):
boolean;
var PIDs: array [0..1024] of DWORD;
    Needed, i: DWORD;
    hProc: THandle;
    curProcName: string;
begin
  Result := False;
  ProcName := ChangeFileExt(ProcName, '.exe');
  if not EnumProcesses(@PIDs, SizeOf(PIDs), Needed) then
    Exit;
  for i := 0 to (Needed div Sizeof(DWORD)) - 1 do begin
    PID := PIDs[i];
    hProc := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,
False, PID);
    if hProc <> 0 then try
      SetLength(curProcName, MAX_PATH);
      if GetModuleBaseNameA(hProc, 0, PChar(curProcName), MAX_PATH) > 0
then begin
        SetLength(curProcName, StrLen(PChar(curProcName)));
        Result := AnsiCompareFileName(curProcName, ProcName) = 0;
        if Result then
          break;
      end;
    finally
      CloseHandle(hProc);
    end;
  end;
end;

...


E come faccio a sapere quando l'applicazione viene chiusa?

 E come faccio a sapere quando l'applicazione viene chiusa?
Dalla domanda mi pare di capire che l'applicazione che devi lanciare
non è un programma in delphi scritto da te e quindi non hai il
codice...altrimenti sull'onclose potevi mettere la cancellazione del
file!!!
Potresti provare con qualche proprietà del form da cui lanci
l'applicazione,cioè quando l'applicazione lanciata viene chiusa il
controllo torna al tuo form generico...,potresti tentare sulle
proprietà on activate,on show del form generico...!Quando vengono
eseguiti questi eventi vuol dire che l'applicazione è terminata (più o
meno) e il controllo è ritornato al tuo programa!

 E come faccio a sapere quando l'applicazione viene chiusa?
...anzi se vuoi ti mando un componente delphi da installare (runprocs)
che serve proprio per vedere i processi attivi!Io ce l'ho su delphi4
ma forse va anche su delphi5...ti prometto che non è un virus!!!

Si mi faresti un grande favore. Puoi inviarmelo a: 
mi...@micla.it

Forse funziona sotto NT ma con Win9x no.

 copia del programma. 
che ne diresti di spiegarci esattamente cosa vuoi ottenere? che 
programma stai scrivendo e cosa deve fare?


 Forse funziona sotto NT ma con Win9x no.
L'esempio (elenco dei task attivi) delle JCL lavora anche sotto 9x.
Semplicemente invece delle psApi linka un'altra dll. Dall'Help delle
JCL:
" Returns the process identifier (PID) for the process identified by
processname.
function GetPidFromProcessName(const ProcessName: string): DWORD;
Unit
JclSysInfo
[...]
Return Value
If the function succeeds it returns the process identifier of the
specified process. If the function fails it returns
INVALID_HANDLE_VALUE. Most common reason of failure is that the
specified process doesn't exist (isn't running) or you didn't specify
the full name of the process.  "
Quindi se sai il nome dell'exe puoi avere il PID; se questo e' INV_H_VAL
il processo non e' attivo.
Saluti
Paolo Arosio

E' probabile che mi sia intricato un pò con gli esempi. Per farla in breve
ho un programma che premendo uno dei tasti funzione lancia un programma
(anche quando questo non è visibile). Io volevo poter lanciare un programma
solo una volta, controllando quindi se questo era già stato lanciato, tutto
quì.

JclSysInfo
Ma da dove scappano fuori?
Io uso D5, forse parliamo di due versioni differenti?

Mino Vitiello,

In uno dei messaggi precedenti c'era l'url del progetto Jedi, che ha
creato le JCL (Jedi Code Library), che e' una libreria open source per
Delphi.
Analogamente hanno creato le JVCL, contenenti componenti.
Uno degli scopi originali dei cavalieri JEDI (Joint Endeavor of Delphi
Innovators) era la traduzione completa degli header delle API Win32 in
OP.
Saluti
Paolo Arosio
ps
Potresti quotare in modo un po' meno sintetico?