You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在SetWindowsHookEx WH_CALLWNDPROC钩子中接收EM_GETTEXTEX时如何获取缓冲区转ANSI

解决方案

核心逻辑说明

WH_CALLWNDPROC钩子会在目标窗口过程接收消息前触发,EM_GETTEXTEX消息的两个参数存储在目标进程的地址空间中,不可直接在钩子进程内解引用:

  • wParam指向GETTEXTEX结构体,存储缓冲区长度、编码格式、标志位等配置
  • lParam指向目标进程分配的文本缓冲区首地址

你现有代码的核心问题是直接访问了目标进程的内存地址,会触发访问越界,必须通过跨进程内存读取接口获取内容。

具体实现步骤

  • 先通过窗口句柄拿到对应进程ID,判断是否为Outlook进程,避免误处理其他程序的同类型消息
  • 调用OpenProcess获取目标进程的内存读取权限
  • 先调用ReadProcessMemory将目标进程中wParam指向的GETTEXTEX结构体读取到本地变量
  • 再调用ReadProcessMemory将目标进程中lParam指向的缓冲区内容读取到本地分配的内存中,读取长度为前面拿到的GETTEXTEX.cb值
  • 若读取到的内容是Unicode编码(Outlook默认使用Unicode),调用WideCharToMultiByte指定CP_ACP转换为ANSI编码即可;若GETTEXTEX.codepage已经配置为ANSI代码页则可直接使用
  • 最后过滤内容中以http/https/ftp开头的字符串即可得到目标超链接URL

修正后核心代码示例

if (nCode < 0)
    return CallNextHookEx(hkb, nCode, wParam, lParam);

CWPSTRUCT* pwsStruct = (CWPSTRUCT*)lParam;
if (pwsStruct->message == EM_GETTEXTEX)
{
    DWORD dwPid = 0;
    GetWindowThreadProcessId(pwsStruct->hwnd, &dwPid);
    // 此处可补充进程名判断逻辑,过滤非Outlook进程
    HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, dwPid);
    if (hProcess == NULL) 
        return CallNextHookEx(hkb, nCode, wParam, lParam);

    GETTEXTEX localGetTextEx = {0};
    SIZE_T dwRead = 0;
    // 第一步:读取目标进程中的GETTEXTEX结构体
    if (ReadProcessMemory(hProcess, (LPCVOID)pwsStruct->wParam, &localGetTextEx, sizeof(GETTEXTEX), &dwRead) && dwRead == sizeof(GETTEXTEX))
    {
        // 分配本地缓冲区
        LPSTR pLocalBuf = (LPSTR)HeapAlloc(GetProcessHeap(), 0, localGetTextEx.cb);
        if (pLocalBuf)
        {
            // 第二步:读取目标进程中的文本内容
            if (ReadProcessMemory(hProcess, (LPCVOID)pwsStruct->lParam, pLocalBuf, localGetTextEx.cb, &dwRead))
            {
                if (localGetTextEx.codepage == CP_UNICODE)
                {
                    // Unicode转ANSI
                    int ansiLen = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pLocalBuf, localGetTextEx.cb / 2, NULL, 0, NULL, NULL);
                    LPSTR pAnsiBuf = (LPSTR)HeapAlloc(GetProcessHeap(), 0, ansiLen + 1);
                    if (pAnsiBuf)
                    {
                        WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pLocalBuf, localGetTextEx.cb / 2, pAnsiBuf, ansiLen, NULL, NULL);
                        pAnsiBuf[ansiLen] = '\0';
                        // 此处pAnsiBuf即为ANSI编码的文本,可直接写入文件或过滤URL
                        writetofile(pAnsiBuf, f1);
                        HeapFree(GetProcessHeap(), 0, pAnsiBuf);
                    }
                }
                else
                {
                    // 已为ANSI编码可直接使用
                    pLocalBuf[localGetTextEx.cb - 1] = '\0';
                    writetofile(pLocalBuf, f1);
                }
            }
            HeapFree(GetProcessHeap(), 0, pLocalBuf);
        }
    }
    CloseHandle(hProcess);
}
return CallNextHookEx(hkb, nCode, wParam, lParam);

优化建议

如果只需捕获用户点击超链接的动作,可以同时HookWM_NOTIFY消息,过滤EN_LINK通知,该通知是RichEdit控件在用户点击超链接时主动触发的,比捕获EM_GETTEXTEX消息准确率更高、性能损耗更小。

内容的提问来源于stack exchange,提问作者Mohammad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 04:15:02