C++ WinEventHook不捕获特定进程id中的事件

C++ WinEventHook不捕获特定进程id中的事件,c++,winapi,event-hooking,C++,Winapi,Event Hooking,我正在创建一个控制台进程,然后尝试使用SetWinEventHook监视它的事件。如果我使用与我创建的进程相关联的PID,我永远不会捕获任何事件。如果我将pid/thread设置为0/0(所有进程/线程),那么我会得到很多结果。我试图连接到特定流程的方式似乎有问题。任何想法都将不胜感激 #include "stdafx.h" #include <windows.h> #include <Oleacc.h> DWORD CreateChildProcess(); voi

我正在创建一个控制台进程,然后尝试使用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("%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;
}
#包括“stdafx.h”
#包括
#包括
DWORD CreateChildProcess();
无效初始化EMSAA(DWORD pid);
void shutdownmsa();
void SetConsoleBufferSize(DWORD processId、短列、短行);
无效回调HandleWinEvent(HWINEVENTHOOK钩子、DWORD事件、HWND HWND、,
长idObject,长idChild,
DWORD dwEventThread、DWORD dwmsEventTime);
HWINEVENTHOOK g_钩;
int main()
{
DWORD pid=CreateChildProcess();
睡眠(5000);
初始化EMSAA(pid);
味精;
while(GetMessage(&msg,NULL,0,0))
{
翻译信息(&msg);
发送消息(&msg);
}
}
//初始化COM并设置事件挂钩。
无效初始化EMSAA(DWORD pid)
{
//初始化组件对象模型库
共初始化(空);
g_hook=SetWinEventHook(
事件\最小值,事件\最大值,//事件范围(控制台)。
NULL,//DLL的句柄。
HandleWinEvent,//回调。
pid,0,//感兴趣的进程和线程ID(0=all)
WINEVENT_out of context);//标志。
//|WINEVENT_Skipown流程
}
//取消事件挂钩并关闭COM。
无效关闭MSAA()
{
脱钩(g_钩);
coninitialize();
}
//处理事件的回调函数。
无效回调HandleWinEvent(HWINEVENTHOOK钩子、DWORD事件、HWND HWND、,
长idObject,长idChild,
DWORD dwEventThread,DWORD dwmsEventTime)
{
IAccessible*pAcc=NULL;
变异瓦尔柴尔德;
HRESULT hr=AccessibleObjectFromEvent(hwnd、idObject、idChild、pAcc和varChild);
如果((hr==S_OK)&&(pAcc!=NULL))
{
BSTR-bstrName;
pAcc->get_accName(varChild和bstrName);
如果(事件==事件\系统\菜单启动)
{
printf(“开始:”);
}
else if(事件==事件\系统\菜单)
{
printf(“结束:”);
}
printf(“%S\n”,bstrName);
SysFreeString(bstrName);
pAcc->Release();
}
}
//创建一个bash子进程,对给定的控制台屏幕缓冲区进行i/o
DWORD CreateChildProcess()
{
//为了在System32中启动bash,程序必须构建为x64
LPCTSTR applicationAddress=L“C:\\Windows\\System32\\bash.exe”;
处理信息piProcInfo;
STARTUPINFO-siStartInfo;
//设置流程信息结构的成员。
SecureZeroMemory(&piProcInfo,sizeof(进程信息));
//设置STARTUPINFO结构的成员。
//此结构指定重定向的STDIN和STDOUT句柄。
SecureZeroMemory(&siStartInfo,sizeof(STARTUPINFO));
siStartInfo.cb=sizeof(STARTUPINFO);
//注意:由于某些原因,初始窗口大小设置不起作用。
自动最小值=GetSystemMetrics(SM_CXMIN);
auto minY=GetSystemMetrics(SM_-CYMIN);
siStartInfo.dwXSize=200;
siStartInfo.dwYSize=200;
//sistarinfo.dwXCountChars=119;
//siStartInfo.dwYCountChars=9;
//sistarinfo.wShowWindow=SW_HIDE;
siStartInfo.dwFlags=STARTF_USESTDHANDLES | STARTF_USESIZE;
//|开始使用ShowWindow |开始使用CountChars
//创建子进程。
BOOL success=CreateProcess(
applicationAddress,//应用程序的绝对路径
TEXT(“-i”),//命令行
NULL,//进程安全属性
NULL,//主线程安全属性
TRUE,//句柄被继承
创建新控制台,//创建标志
NULL,//使用父环境
NULL,//使用父级的当前目录
&siStartInfo,//STARTUPINFO指针
&piProcInfo);//接收进程信息
如果(!成功)
{
int lastError=GetLastError();
}
返回piProcInfo.dwProcessId;
}
如果我使用与我创建的流程关联的PID,我永远不会 捕捉任何事件

原因可能是控制台进程不拥有控制台窗口。控制台窗口与conhost.exe()关联。因此,与控制台窗口相关的消息将由conhost.exe处理,而不是由您创建的进程处理

如果我将pid/thread设置为0/0(所有进程/线程),那么我会得到很多 结果

尝试将PID设置为与您启动的控制台应用程序关联的conhost.exe进程的PID。您现在应该只从控制台窗口接收事件


我认为没有直接的API来查找关联的conhost.exe进程,但您可以尝试枚举新进程的所有子进程,直到找到“conhost.exe”。您可能必须在循环中执行此操作,因为在返回
CreateProcess()
后conhost.exe不会立即出现。

尝试使用notepad.exe。。。。。一切都很好,确实如此。看起来这是控制台应用程序的问题,因为bash.exe和cmd.exe都不会触发任何挂钩!可能……。请注意,文档中对控制台应用程序有一些警告,“在某些情况下,即使您请求WINEVENT_INCONTEXT事件,事件仍将在上下文之外传递。这些情况包括来自控制台窗口的事件和来自具有不同位深度(64位与32位)的进程的事件但这在这里似乎并不适用,因为你的期望是断章取义的。尽管如此,这仍然像是一条线索。您显然在调用Unicode版本的
CreateProcess()
,但您没有通过