我正在创建一个控制台进程,然后尝试使用SetWinEventHook监视它的事件。如果我使用与我创建的进程相关联的PID,我永远不会捕捉到任何事件。如果我将pid/thread设置为0/0(所有进程/线程),那么我会得到很多结果。我试图连接到一个特定过程的方式似乎出了问题。任何想法都将不胜感激。
#include "stdafx.h"
#include <windows.h>
#include <Oleacc.h>
DWORD CreateChildProcess();
void InitializeMSAA(DWORD pid);
void ShutdownMSAA();
void SetConsoleBufferSize(DWORD processId, short columns, short rows);
void CALLBACK HandleWinEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
LONG idObject, LONG idChild,
DWORD dwEventThread, DWORD dwmsEventTime);
HWINEVENTHOOK g_hook;
int main()
{
DWORD pid = CreateChildProcess();
Sleep(5000);
InitializeMSAA(pid);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Initializes COM and sets up the event hook.
void InitializeMSAA(DWORD pid)
{
// Initializes Component Object Model library
CoInitialize(NULL);
g_hook = SetWinEventHook(
EVENT_MIN, EVENT_MAX, // Range of events (Console).
NULL, // Handle to DLL.
HandleWinEvent, // The callback.
pid, 0, // Process and thread IDs of interest (0 = all)
WINEVENT_OUTOFCONTEXT); // Flags.
//| WINEVENT_SKIPOWNPROCESS
}
// Unhooks the event and shuts down COM.
void ShutdownMSAA()
{
UnhookWinEvent(g_hook);
CoUninitialize();
}
// Callback function that handles events.
void CALLBACK HandleWinEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
LONG idObject, LONG idChild,
DWORD dwEventThread, DWORD dwmsEventTime)
{
IAccessible * pAcc = NULL;
VARIANT varChild;
HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &pAcc, &varChild);
if ((hr == S_OK) && (pAcc != NULL))
{
BSTR bstrName;
pAcc->get_accName(varChild, &bstrName);
if (event == EVENT_SYSTEM_MENUSTART)
{
printf("Begin: ");
}
else if (event == EVENT_SYSTEM_MENUEND)
{
printf("End: ");
}
printf("%Sn", bstrName);
SysFreeString(bstrName);
pAcc->Release();
}
}
// Creates a bash child process with i/o to a given console screen buffer
DWORD CreateChildProcess()
{
// In order to launch bash in System32, program must be built as x64
LPCTSTR applicationAddress = L"C:\Windows\System32\bash.exe";
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
// Set up members of the PROCESS_INFORMATION structure.
SecureZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
SecureZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
// NB: Initial window size settings don't work for some reason.
auto minX = GetSystemMetrics(SM_CXMIN);
auto minY = GetSystemMetrics(SM_CYMIN);
siStartInfo.dwXSize = 200;
siStartInfo.dwYSize = 200;
//siStartInfo.dwXCountChars = 119;
//siStartInfo.dwYCountChars = 9;
//siStartInfo.wShowWindow = SW_HIDE;
siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESIZE;
// | STARTF_USESHOWWINDOW | STARTF_USECOUNTCHARS
// Create the child process.
BOOL success = CreateProcess(
applicationAddress, // absolute path to the application
TEXT("-i"), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
CREATE_NEW_CONSOLE, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
if (!success)
{
int lastError = GetLastError();
}
return piProcInfo.dwProcessId;
}
如果我使用与我创建的进程关联的PID,我永远不会捕捉任何事件。
原因可能是控制台进程不拥有控制台窗口。控制台窗口与conhost.exe(在Win 7之前的Windows版本中为csrss.exe)关联。因此,与控制台窗口相关的消息将由conhost.exe处理,而不是由您创建的进程处理。
如果我将pid/thread设置为0/0(所有进程/线程),那么我会得到很多结果。
尝试将PID设置为与您启动的控制台应用程序关联的conhost.exe进程的PID。现在,您应该只从控制台窗口接收事件。
我不认为有一个直接的API可以找到关联的conhost.exe进程,但您可以尝试枚举新进程的所有子进程,直到找到"conhost.exe"。您可能必须在循环中这样做,因为在返回CreateProcess()
后,conhost.exe不会立即出现。