我试图重新实现.NET的Process.Exited
事件,但到目前为止我还没有成功。应用程序未打开时不会返回任何错误。我错过了什么?
#include <stdio.h>
#include <windows.h>
static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut);
int main()
{
char *cmd = "C:\\Windows\\System32\\notepad.exe";
STARTUPINFOA si = { sizeof(STARTUPINFOA) };
//si.cb = STARTUPINFOA.sizeof;
PROCESS_INFORMATION pi;
if(CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DETACHED_PROCESS | CREATE_SUSPENDED, NULL, NULL, &si, &pi))
{
HANDLE hWait;
if(!RegisterWaitForSingleObject(&hWait, pi.hProcess, OnExited, NULL, INFINITE, WT_EXECUTEONLYONCE))
{
printf("register failed! = %d", GetLastError());
}
}
else
{
printf("error = %d\n", GetLastError());
}
}
static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut)
{
printf("OnExited got called!\n");
}
答案 0 :(得分:3)
您正在使用CREATE_SUSPENDED
标记创建新流程,但在注册新流程pi.hThread
后,您没有恢复流程(将ResumeThread()
传递给HANDLE
)通知。即使您这样做,也不会在退出main()
之前等待通知到达。
使用完毕后,您也无法关闭pi.hThread
,pi.hProcess
或hWait
。
尝试更像这样的事情:
#include <stdio.h>
#include <windows.h>
static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut);
int main()
{
char *cmd = "C:\\Windows\\System32\\notepad.exe";
STARTUPINFOA si = {};
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
if (!CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DETACHED_PROCESS | CREATE_SUSPENDED, NULL, NULL, &si, &pi))
{
printf("create process error = %u\n", GetLastError());
}
else
{
HANDLE hWait = NULL;
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!hEvent)
{
printf("create event error = %u\n", GetLastError());
}
else if (!RegisterWaitForSingleObject(&hWait, pi.hProcess, OnExited, hEvent, INFINITE, WT_EXECUTEONLYONCE))
{
printf("register wait error = %u\n", GetLastError());
}
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
if (hEvent)
{
if (hWait)
{
WaitForSingleObject(hEvent, INFINITE);
UnregisterWait(hWait);
}
CloseHandle(hEvent);
}
CloseHandle(pi.hProcess);
}
return 0;
}
static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut)
{
printf("OnExited got called!\n");
SetEvent((HANDLE)context);
}
或者,如果省略CREATE_SUSPENDED
标记,则可以省略ResumeThread()
。只要在等待线程满足之前没有关闭进程句柄,即使进程在等待线程开始监视之前结束,等待通知仍然有效:
#include <stdio.h>
#include <windows.h>
static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut);
int main()
{
char *cmd = "C:\\Windows\\System32\\notepad.exe";
STARTUPINFOA si = {};
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
if (!CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
{
printf("create process error = %u\n", GetLastError());
}
else
{
CloseHandle(pi.hThread);
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!hEvent)
{
printf("create event error = %u\n", GetLastError());
}
else
{
HANDLE hWait = NULL;
if (!RegisterWaitForSingleObject(&hWait, pi.hProcess, OnExited, hEvent, INFINITE, WT_EXECUTEONLYONCE))
{
printf("register wait error = %u\n", GetLastError());
}
else
{
WaitForSingleObject(hEvent, INFINITE);
UnregisterWait(hWait);
}
CloseHandle(hEvent);
}
CloseHandle(pi.hProcess);
}
return 0;
}
static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut)
{
printf("OnExited got called!\n");
SetEvent((HANDLE)context);
}
然而,无论哪种方式,在这样一个简单的控制台应用程序中使用RegisterWaitForSingleObject()
并不是非常有用。相反,它在多线程/ GUI应用程序中更有意义。对于此示例,您只需使用WaitForSingleObject()
:
#include <stdio.h>
#include <windows.h>
int main()
{
char *cmd = "C:\\Windows\\System32\\notepad.exe";
STARTUPINFOA si = {};
si.cb = sizeof(STARTUPINFOA);
PROCESS_INFORMATION pi;
if (!CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
{
printf("create process error = %d\n", GetLastError());
}
else
{
CloseHandle(pi.hThread);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
printf("Exited!\n");
}
return 0;
}
答案 1 :(得分:-1)
我认为这里的基本问题是你的主要过程是终止,即如果你做了类似的事情:
#include <thread>
std::this_thread::sleep_for(std::chrono::seconds(10000));
在主线程上,将调用该处理程序。在您的示例/演示中,您的程序没有其他任何操作。
我的意思是除了CREATE_SUSPENDED之外,它显然做了它所说的,所以你永远不会看到你创建的进程的窗口。
这对我有用:
#include <thread>
#include <iostream>
#include <string>
#include <windows.h>
static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut);
int main()
{
char *cmd = "C:\\Windows\\System32\\notepad.exe";
STARTUPINFOA si = { sizeof(STARTUPINFOA) };
PROCESS_INFORMATION pi;
if (CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
{
HANDLE hWait;
if (!RegisterWaitForSingleObject(&hWait, pi.hProcess, OnExited, NULL, INFINITE, WT_EXECUTEONLYONCE))
{
std::cout << "register failed: " << GetLastError() << std::endl;
}
}
else
{
std::cout << "error creating process: " << GetLastError() << std::endl;
}
// Engage in shenanigans otherwise we'll just exit main.
std::this_thread::sleep_for(std::chrono::seconds(10000));
}
static void CALLBACK OnExited(void* context, BOOLEAN isTimeOut)
{
std::cout << "OnExited got called!" << std::endl;
}
答案 2 :(得分:-3)
你可以使用例如下一个代码:
class __declspec(novtable) _WAIT_CTX
{
HANDLE hObject, WaitHandle;
static VOID CALLBACK _WaitOrTimerCallback(PVOID lpParameter, BOOLEAN /*TimerOrWaitFired*/)
{
reinterpret_cast<_WAIT_CTX*>(lpParameter)->_OnWaitCallback();
}
void _OnWaitCallback()
{
OnWaitCallback(hObject);
delete this;
}
protected:
virtual ~_WAIT_CTX()
{
if (WaitHandle) UnregisterWait(WaitHandle);
if (hObject) CloseHandle(hObject);
}
virtual void OnWaitCallback(HANDLE hObject) = 0;
public:
ULONG Register(HANDLE h)
{
hObject = h;
if (RegisterWaitForSingleObject(&WaitHandle, h,
_WaitOrTimerCallback, this, INFINITE, WT_EXECUTEONLYONCE))
{
return NOERROR;
}
ULONG dwError = GetLastError();
delete this;
return dwError;
}
_WAIT_CTX() : hObject(0), WaitHandle(0)
{
}
};
class WAIT_CTX : public _WAIT_CTX
{
virtual void OnWaitCallback(HANDLE hProcess)
{
ULONG exitCode;
GetExitCodeProcess(hProcess, &exitCode);
DbgPrint("exitcode=%x", exitCode);
}
};
ULONG bbb()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
ULONG dwError;
if (CreateProcessW(L"c:\\windows\\notepad.exe", 0, 0, 0, 0, 0, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);
if (WAIT_CTX* p = new WAIT_CTX)
{
dwError = p->Register(pi.hProcess);
}
else
{
dwError = ERROR_OUTOFMEMORY;
CloseHandle(pi.hProcess);
}
}
else
{
dwError = GetLastError();
}
return dwError;
}