Abrir programa usando o CreateProcess e fechar ao matar o processo do .EXE

Olá pessoal!
Estou usando o código abaixo para abrir um programa.

[code]#include <windows.h>

int main() {
STARTUPINFO infoBina={sizeof(infoBina)};
PROCESS_INFORMATION processInfoBina;
infoBina.dwFlags = STARTF_USESHOWWINDOW;
infoBina.wShowWindow = SW_HIDE;

if (CreateProcess(NULL, "java -jar medfour-technic.jar", NULL, NULL, FALSE,  
        0, NULL, NULL, &infoBina, &processInfoBina)) {
    WaitForSingleObject(processInfoBina.hProcess, INFINITE);
    CloseHandle(processInfoBina.hProcess);
    CloseHandle(processInfoBina.hThread);
}

return 0;

}
[/code]
Este código funciona muito bem.
O EXE abre o meu programa Java, e fica aparecendo no Gerenciador de Tarefas. Mas eu gostaria que, ao matar o processo desse executável no Gerenciador de Processos, que matasse meu programa tbem; igual acontece com o Netbeans.

Como que eu posso fazer?

Até mais

Vê se isso ajuda em alguma coisa: http://stackoverflow.com/questions/268208/delphi-gracefully-closing-created-process-in-service-using-tprocess-createp.
Você deve usar a função GetExitCodeProcess para obter uma variável que armazene o estado do processo. Enumere as janelas abertas pelo sistema, pegue o handle assiciado a essa janela e ese o método PostMessage da seguinte forma:

GetWindowThreadProcessId seta um handle que aponta para a janela associada com o processo do seu aplicativo.
Espero que essas informações lhe ajudem.

Você pode fazer o seguinte. Eu acho que deve ter um modo melhor de fazer, mas acho que isso funciona:

[code]#include <windows.h>

int main() {
STARTUPINFO infoBina={sizeof(infoBina)};
PROCESS_INFORMATION processInfoBina;
//infoBina.dwFlags = STARTF_USESHOWWINDOW;
//infoBina.wShowWindow = SW_HIDE;
DWORD result

if (CreateProcess(NULL, "java -jar medfour-technic.jar", NULL, NULL, FALSE,  
        0, NULL, NULL, NULL, &processInfoBina)) {//Perceba que eu removi o penúltimo parâmetro da função, pois ele é desnecessário.
    while(1)
    {
        result = WaitForSingleObject(processInfoBina.hProcess, INFINITE);//WaitForSingleObject retorna WAIT_OBJECT_0 caso o processo seja encerrado
        if (result = WAIT_OBJECT_0)
        {
             EnumWindows(&finishApp, processInfoBina.dwProcessId);            
             break;
         }
    }
    CloseHandle(processInfoBina.hProcess);
    CloseHandle(processInfoBina.hThread);
}

return 0;

}

BOOL finishApp(hHwnd:HWND; dwData:LPARAM)
{
DWORD vID;
GetWindowThreadProcessID(hHwnd, &vID);
if (vID == dwData)
{
PostMessage(hHwnd, WM_CLOSE, 0, 0);
return False;
}else
{
return True;
}
}
[/code]

Espero que isso resolva seu problema.

Ao usuário entanglement: existe alguma forma mais elegante de se fazer isso?

Olá!

Obrigada pela ajuda, mas o código tá dando um erro de compilação na linha 16 :frowning:

O que pode estar acontecendo?

[code]#include <windows.h>

BOOL finishApp(HWND hHwnd, LPARAM dwData);

int main() {
STARTUPINFO infoBina={sizeof(infoBina)};
PROCESS_INFORMATION processInfoBina;
DWORD result;

if (CreateProcess(NULL, "java -jar medfour-technic.jar", NULL, NULL, FALSE,
        0, NULL, NULL, NULL, &processInfoBina)) {
    while(1) {
        result = WaitForSingleObject(processInfoBina.hProcess, INFINITE);
        
        if (result = WAIT_OBJECT_0) {
             EnumWindows(&finishApp, processInfoBina.dwProcessId);
             break;
         }
    }
    CloseHandle(processInfoBina.hProcess);
    CloseHandle(processInfoBina.hThread); 
}
  
return 0;  

}

BOOL finishApp(HWND hHwnd, LPARAM dwData) {
DWORD vID;
GetWindowThreadProcessId(hHwnd, &vID);
if (vID == dwData) {
PostMessage(hHwnd, WM_CLOSE, 0, 0);
return FALSE;
}else {
return TRUE;
}
}
[/code]

Obrigada

Ficou faltando um cast:

[code]#include <windows.h>

BOOL finishApp(HWND hHwnd, LPARAM dwData);

int main() {
STARTUPINFO infoBina={sizeof(infoBina)};
PROCESS_INFORMATION processInfoBina;
DWORD result;

if (CreateProcess(NULL, "java -jar medfour-technic.jar", NULL, NULL, FALSE,
        0, NULL, NULL, NULL, &processInfoBina)) {
    while(1) {
        result = WaitForSingleObject(processInfoBina.hProcess, INFINITE);
        
        if (result = WAIT_OBJECT_0) {
             EnumWindows((WNDENUMPROC)&finishApp, processInfoBina.dwProcessId);
             break;
         }
    }
    CloseHandle(processInfoBina.hProcess);
    CloseHandle(processInfoBina.hThread); 
}
  
return 0;  

}

BOOL finishApp(HWND hHwnd, LPARAM dwData) {
DWORD vID;
GetWindowThreadProcessId(hHwnd, &vID);
if (vID == dwData) {
PostMessage(hHwnd, WM_CLOSE, 0, 0);
return FALSE;
}else {
return TRUE;
}
}
[/code]

Veja se dá certo agora.

Obrigada pela ajuda e desculpe pelas perguntas, mas não sou programadora C… :oops: eu arranho aqui pra fazer as coisas que eu preciso…

Compilou aqui certinho, mas quando eu executo o EXE, dá a seguinte mensagem: O medfour.exe encontrou um problema e precisa ser fechado.
O que pode estar gerando erro aqui?

Obrigada

Olá!

Consegui fazer funcionar!
Coloquei de volta o código:

infoBina.dwFlags = STARTF_USESHOWWINDOW; infoBina.wShowWindow = SW_HIDE;
e o programa parou de dar aquela msg de erro do Windows.

[code]#include <windows.h>

BOOL finishApp(HWND hHwnd, LPARAM dwData);

int main() {
STARTUPINFO infoBina={sizeof(infoBina)};
PROCESS_INFORMATION processInfoBina;
infoBina.dwFlags = STARTF_USESHOWWINDOW;
infoBina.wShowWindow = SW_HIDE;
DWORD result;

if (CreateProcess(NULL, "java -jar medfour-technic.jar", NULL, NULL, FALSE,
        0, NULL, NULL, &infoBina, &processInfoBina)) {
    while(1) {
        result = WaitForSingleObject(processInfoBina.hProcess, INFINITE);
        
        if (result = WAIT_OBJECT_0) {
             EnumWindows((WNDENUMPROC)&finishApp, processInfoBina.dwProcessId);
             break;
         }
    }
    CloseHandle(processInfoBina.hProcess);
    CloseHandle(processInfoBina.hThread); 
}
  
return 0;  

}

BOOL finishApp(HWND hHwnd, LPARAM dwData) {
DWORD vID;
GetWindowThreadProcessId(hHwnd, &vID);
if (vID == dwData) {
PostMessage(hHwnd, WM_CLOSE, 0, 0);
return FALSE;
}else {
return TRUE;
}
}[/code]

A única coisa que eu não consigo entender é que, quando eu fecho o meu executável pelo Gerenciador de Tarefas, ele não está fazendo o que eu quero, que é fechar a minha aplicação java :frowning:

Obrigada

O seu problema é que você gostaria de ter um relacionamento pai-filho entre processos, que é uma coisa que não existe “por padrão” no Windows.

Não sei se isso ajuda:

http://msdn.microsoft.com/en-us/library/ms684161(v=VS.85).aspx#creating_jobs

Tenta assim agora:

[code]#include <windows.h>

BOOL finishApp(HWND hHwnd, LPARAM dwData);

int main() {
STARTUPINFO infoBina={sizeof(infoBina)};
PROCESS_INFORMATION processInfoBina;
infoBina.dwFlags = STARTF_USESHOWWINDOW;
infoBina.wShowWindow = SW_HIDE;
UINT status;

if (CreateProcess(NULL, "java -jar medfour-technic.jar", NULL, NULL, FALSE,
        0, NULL, NULL, &infoBina, &processInfoBina)) {
    WaitForSingleObject(processInfoBina.hProcess, INFINITE);
    while(1) {
		GetExitCodeProcess(processInfoBina.hProcess, (LPDWORD)status);
		if (status != STILL_ACTIVE) {
			 EnumWindows((WNDENUMPROC)&finishApp, processInfoBina.dwProcessId);
             break;
         }
    }
    CloseHandle(processInfoBina.hProcess);
    CloseHandle(processInfoBina.hThread); 
}
  
return 0;  

}

BOOL finishApp(HWND hHwnd, LPARAM dwData) {
DWORD vID;
GetWindowThreadProcessId(hHwnd, &vID);
if (vID == dwData) {
PostMessage(hHwnd, WM_CLOSE, 0, 0);
return FALSE;
}else {
return TRUE;
}
}[/code]

O problema é detectar o momento em que o processo é encerrado.
Fazendo isso, pode-se chamar a função EnumWindows, passando como parâmetro o callback de finishApp e o ID do processo. Essa função EnumWindows procura janelas que estejam associadas com o processo definido pelo parâmetro ID e faz com essa janela o que foes específicado pela função que EnumWindows recebe como parâmetro. Nesse caso, EnumWindow recebe como parâmetro a função finishApp e essa função encerra a aplicação através da seguinte chamada:

Onde esse hhwnd é um handle (ponteiro) para a Janela da aplicação.

[quote=entanglement]O seu problema é que você gostaria de ter um relacionamento pai-filho entre processos, que é uma coisa que não existe “por padrão” no Windows.

Não sei se isso ajuda:

http://msdn.microsoft.com/en-us/library/ms684161(v=VS.85).aspx#creating_jobs
[/quote]

Olá entanglement!
Pesquisei bastante sobre o link que vc me passou, e saiu esse código abaixo… mas acho que tem algo de errado, porque eu não tou conseguindo matar o processo do Java junto com o meu executável.

[code]#define _WIN32_WINNT 0x0500

#include <Windows.h>
#include <Winbase.h>

int main() {
STARTUPINFO infoBina = {sizeof(infoBina)};
PROCESS_INFORMATION processInfoBina;
infoBina.dwFlags = STARTF_USESHOWWINDOW;
infoBina.wShowWindow = SW_MINIMIZE;

HANDLE job = CreateJobObject(NULL, "medfour");
AssignProcessToJobObject(job, processInfoBina.hProcess);

if (CreateProcess(NULL, "java -jar medfour-technic.jar", NULL, NULL, FALSE,
        0, NULL, NULL, &infoBina, &processInfoBina)) {
    
    WaitForSingleObjectEx(processInfoBina.hProcess, INFINITE, TRUE);
    
    TerminateJobObject(job, 0);
    CloseHandle(processInfoBina.hProcess);  
    CloseHandle(processInfoBina.hThread);  
}
  
return 0;

}[/code]

Obrigada

Acho que esse TerminateJobObject que você criou não está certo.
Ele recebe como parâmetro um handle para para o Job que você criou. Até ai tá certo. Mas o segundo parâmetro é o código de saída do seu processo. E pelo que consta na API, 0 é quando o processo apresanta uma falha de execução. Você deve usar GetExitCodeProcess para obter o valor que será passado como parâmetro para TerminateJobObject. Veja se é isso.

[quote=eliangela][quote=entanglement]O seu problema é que você gostaria de ter um relacionamento pai-filho entre processos, que é uma coisa que não existe “por padrão” no Windows.

Não sei se isso ajuda:

http://msdn.microsoft.com/en-us/library/ms684161(v=VS.85).aspx#creating_jobs
[/quote]

Olá entanglement!
Pesquisei bastante sobre o link que vc me passou, e saiu esse código abaixo… mas acho que tem algo de errado, porque eu não tou conseguindo matar o processo do Java junto com o meu executável.

[code]#define _WIN32_WINNT 0x0500

#include <Windows.h>
#include <Winbase.h>

int main() {
STARTUPINFO infoBina = {sizeof(infoBina)};
PROCESS_INFORMATION processInfoBina;
infoBina.dwFlags = STARTF_USESHOWWINDOW;
infoBina.wShowWindow = SW_MINIMIZE;

HANDLE job = CreateJobObject(NULL, "medfour");
AssignProcessToJobObject(job, processInfoBina.hProcess);

if (CreateProcess(NULL, "java -jar medfour-technic.jar", NULL, NULL, FALSE,
        0, NULL, NULL, &infoBina, &processInfoBina)) {
    
    WaitForSingleObjectEx(processInfoBina.hProcess, INFINITE, TRUE);
    
    TerminateJobObject(job, 0);
    CloseHandle(processInfoBina.hProcess);  
    CloseHandle(processInfoBina.hThread);  
}
  
return 0;

}[/code]

Obrigada[/quote]

Acabei de notar uma coisa estranha no seu código. Você tá associando o Job com um processo que ainda não foi criado. Não seria o certo chamar o create process e depois passar o handle desse processo para a função AssignProcessToJobObject? Porque da forma que está, quando você encerrar o Job, o processo da sua aplicação Java não será encerrado.

Humm, vou ver se é isso que vc disse, porque eu li no site http://msdn.microsoft.com/en-us/library/ms684161%28v=VS.85%29.aspx#creating_jobs e eu entendi que era essa ordem aí… :?:

Vou verificar isso aqui… acho que amanhã cedo consigo postar alguma resposta aqui.

Obrigada

[quote=matheuslmota]Acho que esse TerminateJobObject que você criou não está certo.
Ele recebe como parâmetro um handle para para o Job que você criou. Até ai tá certo. Mas o segundo parâmetro é o código de saída do seu processo. E pelo que consta na API, 0 é quando o processo apresanta uma falha de execução. Você deve usar GetExitCodeProcess para obter o valor que será passado como parâmetro para TerminateJobObject. Veja se é isso.
[/quote]

Vou tentar isso tbem.
Obrigada

Humm, vou ver se é isso que vc disse, porque eu li no site http://msdn.microsoft.com/en-us/library/ms684161%28v=VS.85%29.aspx#creating_jobs e eu entendi que era essa ordem aí… :?:

Vou verificar isso aqui… acho que amanhã cedo consigo postar alguma resposta aqui.

Obrigada[/quote]

Mas a ordem é essa mesmo. O que tá errado é que você tá passando para o AssignProcessToJobObject um handle que era pra apontar pra um processo, mas que na verdade não aponta para nada:

[code] HANDLE job = CreateJobObject(NULL, “medfour”);
AssignProcessToJobObject(job, processInfoBina.hProcess); //processInfoBina.hProcess ainda não foi inicializado. O Job foi associado a um processo que ainda não existe

if (CreateProcess(NULL, "java -jar medfour-technic.jar", NULL, NULL, FALSE,
        0, NULL, NULL, &infoBina, &processInfoBina)) { Aqui o processInfoBina.hProcess foi inicializado, mas o Job não tem ciencia da existência desse processo
    
    WaitForSingleObjectEx(processInfoBina.hProcess, INFINITE, TRUE);
    
    TerminateJobObject(job, 0);
    CloseHandle(processInfoBina.hProcess);  
    CloseHandle(processInfoBina.hThread);  
}[/code]