I'm creating a console process and then trying to monitor it for events with SetWinEventHook. If I use the PID associated with the process I've created, I never catch any events. If I set pid/thread to 0/0 (all processes/threads) then I get plenty of results. It seems like something is wrong in the way I'm trying to hook to a specific process. Any ideas would be appreciated.
#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("%S\n", 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;
}
If I use the PID associated with the process I've created, I never catch any events.
The reason for that propably is that a console process does not own the console window. The console window is associated with conhost.exe (csrss.exe in versions of Windows prior to Win 7). So the messages related to the console window will be processed by conhost.exe, not the process you created.
If I set pid/thread to 0/0 (all processes/threads) then I get plenty of results.
Try to set the PID to that of the conhost.exe process associated with the console application you launched. You should now receive the events only from the console window.
I don't think there is a direct API to find the associated conhost.exe process but you could try to enumerate all child processes of the new process until you have found "conhost.exe". You propably have to do this in a loop as conhost.exe won't be there immediately after CreateProcess()
returned.