La Web del Programador: Comunidad de Programadores
 
    Pregunta:  19492 - CERRAR EL PROGRAMA ABIERTO CON LA INSTRUCCION SHELL
Autor:  Juan M. Gómez
Tras no poder ejecutar un archivo de ayuda HTML que yo mismo he creado y compilado para mi programa con el HTML Help Workshop, un amigo me recomendó usar la función Shell para llamar al hh.exe y abir el archivo de ayuda mencionado. Mi problema es ahora que no encuentro la forma de cerrar este archivo mediante código para que no quede abierto en caso de cerrar antes el programa.

En la bibliografía y en el MSDN citan la utilización de CommonDialog para abrir y cerrar archivos de ayuda, pero parece ser que esto no funciona correctamente con ayuda en chm (HTML).

Gracias.

  Respuesta:  Javier Perez
Para poder finalizar un programa llamada desde el tuyo, incluye las siguientes declaraciones en un módulo:

Private Const NORMAL_PRIORITY_CLASS = &H20&

Private Const GW_HWNDNEXT = 2
Private Const GW_CHILD = 5

Public Const WM_CLOSE = &H10

Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" ( _
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 lpCurrentDriectory As Long, _
lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long

Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Declare Function GetTopWindow Lib "user32" (ByVal hwnd As Long) As Long
Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long

Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Private 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

Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessId As Long
dwThreadID As Long
End Type

Public Function EjecutarProceso(lpApp As String, lpCmd As String, lpDir As String) As Long

Dim cmd As String
Dim proc As PROCESS_INFORMATION
Dim start As STARTUPINFO
Dim ret As Long

' Inicializamos la estructura STARTUPINFO
start.cb = Len(start)

' Iniciamos la aplicación
cmd = """" + lpDir + "\" + lpApp + """ " + lpCmd
ret = CreateProcess(0&, cmd, 0&, 0&, 1&, NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)

If ret <> 0 Then
' Devolvemos el handle del proceso iniciado
EjecutarProceso = proc.dwProcessId

Else
' Error; devolvemos 0 como handle no válido
EjecutarProceso = 0
End If
End Function

Public Function ObtenerVentanaProceso(hproceso As Long) As Long

Dim hwnd As Long
Dim hProcessId As Long
Dim hThreadId As Long

' Obtenemos el identificador de la ventana de nivel superior
hwnd = GetTopWindow(0)
Do
' Obtenemos el identificador del proceso creador de la ventana
hThreadId = GetWindowThreadProcessId(hwnd, hProcessId)

If hProcessId = hproceso Then
' Es una ventana del proceso buscado; comprobamos si es una ventana padre
If GetWindow(hwnd, GW_CHILD) <> 0 Then
' Encontrada la ventana buscada
Exit Do
End If
End If

hwnd = GetWindow(hwnd, GW_HWNDNEXT)
Loop Until hwnd = 0

ObtenerVentanaProceso = hwnd

End Function

Para ejecutar el programa que te interese, haz entonces la siguiente llamada:

Dim hProceso As Long
Dim params As String
Dim ruta As String
params = "..." ' Los parámetros necesarios para el programa llamado
ruta = "..." ' Ruta del programa llamado
hProceso = EjecutarProceso("programa.exe", params, ruta)

Para finalizar el programa, haz entonces lo siguiente:

Dim hwnd As Long

If hProceso <> 0 Then
hwnd = ObtenerVentanaProceso(hProceso)
If hwnd <> 0 Then Call PostMessage(hwnd, WM_CLOSE, 0, 0)
End If