Newsgroup: it.comp.lang.visual-basic
Titolo: Si puo' intercettare la chisusura di un programma?

Apro un file col programma associato utilizzando ShellExecute. C'e' la 
possibilita' di intercettare quando tale programma termina?
Per esempio OpenFile Me.hwnd, file.pdf mi apre acrobat e mi fa visualizzare 
file.pdf, ma quando chiudo l'acrobat il mio programma deve rimuovere il file 
appena visualizzato.
Si puo' fare? 

 [...]
Non so se questo e' precisamente cio' che ti serve, ma c'e' la possibilita' 
di avviare un eseguibile ed attendere la sua chiusura.
Riporto in calce alla mail un esempio che trovai qualche anno fa in rete. 
Purtroppo non ricordo la fonte... forse il sito comune...?
Ciao!
    Alex
Public Type STARTUPINFO
        cb As Long
        lpReserved As String
        lpDesktop As String
        lpTitle As String
        dwX As Long
        dwY As Long
        dwXSize As Long
        dwYSize As Long
        dwXCountChars As Long
        dwYCountChars As Long
        dwFillAttribute As Long
        dwFlags As Long
        wShowWindow As Integer
        cbReserved2 As Integer
        lpReserved2 As Long
        hStdInput As Long
        hStdOutput As Long
        hStdError As Long
End Type
Public Type PROCESS_INFORMATION
        hProcess As Long
        hThread As Long
        dwProcessID As Long
        dwThreadID As Long
End Type
Public Declare Function WaitForSingleObject Lib "kernel32" (ByVal _
        hHandle As Long, ByVal dwMilliseconds As Long) As Long
Public Declare Function CreateProcessA Lib "kernel32" (ByVal _
        lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _
        lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _
        ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
        ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _
        lpStartupInfo As STARTUPINFO, lpProcessInformation As _
        PROCESS_INFORMATION) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal _
        hObject As Long) As Long
Public Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" 
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, 
ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As 
Long) As Long
Public Const TH32CS_SNAPHEAPLIST = &H1&
Public Const TH32CS_SNAPPROCESS = &H2&
Public Const TH32CS_SNAPTHREAD = &H4&
Public Const TH32CS_SNAPMODULE = &H8&
Public Const TH32CS_INHERIT = &H80000000
Public Const SW_SHOWNORMAL = 1
Public Const NORMAL_PRIORITY_CLASS = &H20&
Public Const INFINITE = -1&
'#########################################################
'Funzione per lanciare un programma in sincrono.
'Il programma lanciato in finestra viene 'atteso' per
'tutta la sua durata.
'Una funzione usata per lanciare un programma MS-DOS
'e attendere la sua fine.
'#########################################################
Public Sub ShellAndWait(ByVal RunProg As String)
    Dim retVal As Long
    Dim proc As PROCESS_INFORMATION
    Dim StartInf As STARTUPINFO
    StartInf.cb = Len(StartInf)
    'Crea sessione del programma da lanciare
    retVal = CreateProcessA(0&, RunProg, 0&, 0&, 1&, NORMAL_PRIORITY_CLASS, 
0&, 0&, StartInf, proc)
    retVal = WaitForSingleObject(proc.hProcess, INFINITE)
    retVal = CloseHandle(proc.hProcess)
End Sub

 possibilita'
Intanto ti ringrazio.
Poi ti faro' sapere se e' risolutivo.
Ciao. 

 wrote in message
news:dkpujn$md7$
1...@newsreader.mailgate.org

Occorre capire se la tua esigenza è di sospendere il codice
finchè il tuo applicativo non viene terminato, oppure se devi
proprio intercettare la chiusura indipendentemente.
Nel primo caso puoi aprire un processo passando il PID restituito
dalla ShellExecute e sfruttare WaitForSingleObject.
Nel 2° caso potresti ricavare l'Hwnd dal PID tramite la funzione
sotto, quindi su Evento Timer testare se l'Handle esiste ancora
con l'API IsWindow(hwnd)
Function InstanceToWnd(ByVal target_pid As Long) As Long
    Dim test_hwnd As Long, test_pid As Long, test_thread_id As Long
    'Find the first window
    test_hwnd = FindWindow(ByVal 0&, ByVal 0&)
    Do While test_hwnd <> 0
        'Check if the window isn't a child
        If GetParent(test_hwnd) = 0 Then
            'Get the window's thread
            test_thread_id = GetWindowThreadProcessId(test_hwnd,
test_pid)
            If test_pid = target_pid Then
                InstanceToWnd = test_hwnd
                Exit Do
            End If
        End If
        'retrieve the next window
        test_hwnd = GetWindow(test_hwnd, GW_HWNDNEXT)
    Loop
End Function
Ciao
@Alex
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 dalla ShellExecute e sfruttare WaitForSingleObject.
Ti ringrazio per avermi risposto.
Il mio caso e' proprio questo, devo attendere la chiususra del pragramma 
lanciato con per andare avanti, quindi usare WaitForSingleObject mi sta 
bene.
Ho pero' un altro piccolo problema.... non riesco ad ottenere il ProcessID 
del programma avviato da ShellExecute!
se faccio hProg = ShellExecute(hwnd, Operation, File, Param, Dir, 1) in 
hProg non ottengo il pid del processo come succede invece con shell(..) ma 
ottengo l'handle interno all'istanza... non so se mi sono spiegato bene.
Come posso aggirare il problema? Come posso ottenre il pid assegnato dal 
S.O. all'applicativo lanciato da ShellExecute?
Grazie 1000. 

 con l'API IsWindow(hwnd)
Scusate se mi allaccio, ho un problema simile.
Necessità:
- Lanciare un file e farlo aprire col programma associato (ShellExecute)
- Interrompere il programma VB
- Quando chiudo il programma aperto (Word, Acrobat, AcdSee) devo riprendere
l'esecuzione del mio programma
C'è il modo di farlo?
Perchè la ShellExecute mi da:
Declare Function ShellExecute Lib "shell32.dll" Alias _
      "ShellExecuteA" (ByVal hWnd As Long, ByVal lpOperation As _
      String, ByVal lpFile As String, ByVal lpParameters As String, _
      ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
E io la richiamo con (preso da google tempo fa):
aa = ShellExecute(Me.hWnd, vbNullString, appo$, vbNullString, "",
SW_SHOWNORMAL)
Una volta richiamata come posso fare ad interrompere il codice?
In aa ho un Long che posso usare con WaitForSingle Object? Mi pare
all'epoca provai ma non riuscii a far nulla :\
Tnx


Rispondo ad entrambi.
La ShellExecute non restituisce un "vero" hInstance (come Shell).
Occorre usare la ShellExecuteEx, che accetta come parametro una struttura in cui
uno dei campi viene riempito opzionalmente (settando un apposito bit nel campo
fMask) con l'handle del processo che *eventualmente* viene avviato.
Questo handle si può usare con la WaitForSingleObject per sincronizzare il
processo chiamante.
Date un'occhiata qui:
http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/structures/shellexecuteinfo.asp
Ciao
Raf

 processo chiamante.
Allora ho fatto cosě:
    Dim se As SHELLEXECUTEINFO
       With se
        .fMask = SEE_MASK_NOCLOSEPROCESS 
        .hwnd = Me.hwnd    ' My forms hWnd
        .lpVerb = "open" ' I want to print the document
        .lpFile = appo$   ' Should execute Notepad.exe
        .cbSize = Len(se)
    End With
    hret = ShellExecuteEx(se)
    Do
      zz = WaitForSingleObject(se.hInstApp, 1000)
      DoEvents
    Loop
Ma in zz ho sempre -1 anche se chiudo il processo.
se.hInstApp mi da un numero tipo 20.325 ecc.
Inoltre con appo$ non apre sempre il file.
Il mio appo$ puň essere
C:\prova.exe
C:\prova.doc
C:\prova.txt
C:\prova.gif
ecc.
Insomma qualsiasi file con estensione :)
Grazie ancora

     Loop
Non devi usare se.hInstApp, ma se.hProcess.
Ciao

 Allora ho fatto cosě:
Cosě Funziona!!!
Public Const SEE_MASK_NOCLOSEPROCESS = &H40
Public Const SW_SHOWNORMAL = 1
Poi all'evento che si vuole
Dim se As SHELLEXECUTEINFO
With se
  .fMask = SEE_MASK_NOCLOSEPROCESS 
  .hwnd = Me.hwnd    ' My forms hWnd
  .lpVerb = "open" ' I want to print the document
  .lpFile = PathFile$   ' Should execute Notepad.exe
  .nShow = SW_SHOWNORMAL '
  .cbSize = Len(se)
End With
retval = ShellExecuteEx(se)
If retval = 0 Then
'errore
Else
  Do
    DoEvents
    retval = WaitForSingleObject(se.hProcess, 0)
  Loop While retval <> 0
End If
Grazie moltissimo a tutti :)

 Non devi usare se.hInstApp, ma se.hProcess.
Sisi, ma non mi funzionava perchč non avevo dichiarato la costante.
Ho fatto una function per chi interessasse (alla memoria di google):
Si richiama cosě:
    appo$="C:\pippo.doc" 'path del file	
    aa = RunAndWait(appo$, Me.hWnd)
    If aa <> "" Then
      MsgBox aa, vbCritical, NOMEPRG
    End If
In un modulo mettere:
Public Const SEE_MASK_NOCLOSEPROCESS = &H40
Global Const SW_SHOWNORMAL = 1
Declare Function ShellExecuteEx Lib "Shell32" Alias "ShellExecuteExA"
(lpExecInfo As SHELLEXECUTEINFO) As Long
 Type SHELLEXECUTEINFO
        cbSize As Long
        fMask As Long
        hWnd As Long
        lpVerb As String
        lpFile As String
        lpParameters As String
        lpDirectory As String
        nShow As Long
        hInstApp As Long
     '  Optional fields
        lpIDList As Long
        lpClass As String
        hkeyClass As Long
        dwHotKey As Long
        hIcon As Long
        hProcess As Long
End Type
Public Function RunAndWait(PathFile$, hwndForm) As String
'Funzione che mi lancia un qualsiasi file con il programma
'associato.
'Es. pathfile="C:\pippo.doc" e hwndfor=me.hwnd
Dim RetVal As Long
Dim se As SHELLEXECUTEINFO
With se
  .fMask = SEE_MASK_NOCLOSEPROCESS
  .hWnd = hwndForm    ' form hWnd
  .lpVerb = "open"
  .lpFile = PathFile$   'Apro File
  .nShow = SW_SHOWNORMAL
  .cbSize = Len(se)
End With
RetVal = ShellExecuteEx(se)
If RetVal = 0 Then
  RunAndWait = "Errore nell'esecuzione dell'applicazione"
  Exit Function
Else
  Do
    DoEvents
    RetVal = WaitForSingleObject(se.hProcess, 0)
  Loop Until RetVal = 0
End If
RunAndWait = ""
End Function

 wrote in message
news:dksdvl$h4j$
1...@newsreader.mailgate.org

Se vuoi usare le API Rafunk ha dato tutte le informazioni
necessarie per farlo, altrimenti per semplificare la cosa
puoi provare questo:
Sub MyShell(ByVal Percorso As String, _ 
            ByVal windowstyle As Integer, _ 
            ByVal Attendi As Boolean) 
   Dim wshell As Object 
   Set wshell = CreateObject("WScript.shell") 
   wshell.Run Percorso, windowstyle, Attendi 
   Set wshell = Nothing 
End Sub 


 Si puo' fare?
Un grazie di cuore a tutti.
Con i vostri utili consigli sono finalmente riuscito ad ottenere il 
risultato sperato.
Volevo aggiungere una cosa.Tra tutti i NG che frequento questo e' in 
assoluto quello dove la professionalita' e la precisione nel dare le 
risposte la fa da padrona, complimenti a tutti.
Buon lavoro. 

"Davide D'Amico" ha scritto nel messaggio

Vedo che hai già risolto. Volevo solo aggiungere che se la tua esigenza
è solo di visualizzare un PDF, puoi inserire l'OCX del visualizzatore
direttamente all'interno del tuo programma. Volendo, se usi l'Acrobat
completo, potresti importare perfino l'intero oggetto, e smanettarci sopra.
Se ti servono altre info, cerca su Google gruppi in questo NG con
chiavi di ricerca "pdf ocx".
Bye, G.

 chiavi di ricerca "pdf ocx".
pdf.ocx fino alla versione 6 di AR; AcroPDF.dll a partire dalla 7.
    Alex