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

15 respostas
E
Olá pessoal! Estou usando o código abaixo para abrir um programa.
#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;
}
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

15 Respostas

M

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.

M
Você pode fazer o seguinte. Eu acho que deve ter um modo melhor de fazer, mas acho que isso funciona:
#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;
     }
}

Espero que isso resolva seu problema.

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

E

Olá!

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

invalid conversion from `BOOL (*)(HWND__*, LPARAM)' to `BOOL (*)(HWND__*, LPARAM)'
O que pode estar acontecendo?
#include &lt;windows.h&gt;

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;
    }
}

Obrigada

M

Ficou faltando um cast:

#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;
    }
}

Veja se dá certo agora.

E

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

E

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.
#include &lt;windows.h&gt;

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;
    }
}

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 :(

Obrigada

E

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

M
Tenta assim agora:
#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;
    }
}
M

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.

E
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%28v=VS.85%29.aspx#creating_jobs

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.

#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;
}

Obrigada

M

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.

M
eliangela:
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%28v=VS.85%29.aspx#creating_jobs

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.

#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;
}

Obrigada

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.

E

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

E

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.

Vou tentar isso tbem.
Obrigada

M
eliangela:
matheuslmota:
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 [url]http://msdn.microsoft.com/en-us/library/ms684161%28v=VS.85%29.aspx#creating_jobs[/url] e eu entendi que era essa ordem aí... :?:

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

Obrigada

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:
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);  
    }
Criado 26 de julho de 2011
Ultima resposta 27 de jul. de 2011
Respostas 15
Participantes 3