V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ck125s
V2EX  ›  C++

[有偿] 小白, Windows UI Automation TextPattern 检测问题求助

  •  
  •   ck125s · 5 小时 48 分钟前 · 410 次点击

    各位 V 友,最近在用 UI Automation (UIA) 时遇到了一个很奇怪的问题,卡了好几天了。

    若方法有效感谢🙏200RMB

    目标: 获取记事本( Notepad )编辑框的 TextPattern 。

    现象:

    我用 Accessibility Insights for Windows 去看,明明确确显示记事本的编辑框是支持 TextPattern 的。

    Accessibility Insights for windows

    问题:

    我自己的代码,无论用哪种方式,都检测不到 TextPattern 。

    我试过的两种方法:

    C++ 原生 COM 接口:

    通过 GetFocusedElement 拿到元素,然后 GetCurrentPattern(TextPattern.Pattern),结果是拿不到。

    C# + Axe.Windows (Accessibility Insights 核心库):

    我以为是我的姿势不对,[找到源码]( GitHub - microsoft/accessibility-insights-windows: Accessibility Insights for Windows),引用 Axe.Windows 库,完全模拟 AI 的工作流程,调用 PopulateAllPropertiesWithLiveData() 等方法,结果依然检测不到 TextPattern 。

    已排除的常规问题:

    UIAccess 权限、COM 线程模型( STA )、元素句柄有效性等都检查过了,没问题。其他 Pattern 比如 ValuePattern 是可以正常获取的。

    核心疑问:

    Accessibility Insights 到底用了什么魔法? 为什么它能看到 TextPattern ,而我直接调用 UIA API 或者用它的核心库都复现不了?是不是需要什么特殊的初始化步骤,或者 Windows 对记事本这个“亲儿子”有什么特殊的处理? 有大佬了解其中机制吗?或者有其他调试思路也行。


    如果能提供解决方案或关键思路,可有偿指导,感谢!

    微信:Delightpl

    8 条回复    2025-09-04 14:46:15 +08:00
    dandycheung
        1
    dandycheung  
       5 小时 24 分钟前 via Android
    看你这过程,不像是小白啊。你要是能把你说的那个软件自己编译成功,逐步调试的话,会不会好点?还有就是有没可能是人家的 manifest 里向系统申请了什么权限之类的,而你自己的落下了?好久不玩 Windows 编程了, 纯属瞎蒙啊。主要是拒绝 0 回复……
    dereklu4
        2
    dereklu4  
       4 小时 30 分钟前
    请问是要这种效果吗
    ![image]( https://imgur.com/a/sP1z8VF)
    dereklu4
        3
    dereklu4  
       4 小时 23 分钟前
    ck125s
        4
    ck125s  
    OP
       4 小时 23 分钟前
    @dereklu4 是的,方便加你微信咨询吗
    ck125s
        5
    ck125s  
    OP
       4 小时 22 分钟前
    @dandycheung 好的 谢谢老哥
    dereklu4
        6
    dereklu4  
       4 小时 20 分钟前
    maggch97
        7
    maggch97  
       1 小时 57 分钟前


    让 AI 写的,好像一次过

    ```
    #include <iostream>
    #include <windows.h>
    #include <comdef.h>
    #include <UIAutomation.h>
    #include <atlbase.h>
    #include <thread>
    #include <chrono>

    #pragma comment(lib, "ole32.lib")
    #pragma comment(lib, "oleaut32.lib")

    HWND consoleWindow = nullptr;
    std::wstring lastSelectedText;

    HRESULT GetTextFromActiveWindow(IUIAutomation* automation, std::wstring& selectedText) {
    HWND foregroundWindow = GetForegroundWindow();
    if (!foregroundWindow || foregroundWindow == consoleWindow) {
    return E_FAIL;
    }

    CComPtr<IUIAutomationElement> windowElement;
    HRESULT hr = automation->ElementFromHandle(foregroundWindow, &windowElement);
    if (FAILED(hr) || !windowElement) {
    return hr;
    }

    CComPtr<IUIAutomationTextPattern> textPattern;
    hr = windowElement->GetCurrentPatternAs(UIA_TextPatternId, IID_PPV_ARGS(&textPattern));
    if (FAILED(hr) || !textPattern) {
    CComPtr<IUIAutomationElement> focusedElement;
    hr = automation->GetFocusedElement(&focusedElement);
    if (FAILED(hr) || !focusedElement) {
    return hr;
    }
    hr = focusedElement->GetCurrentPatternAs(UIA_TextPatternId, IID_PPV_ARGS(&textPattern));
    if (FAILED(hr) || !textPattern) {
    return hr;
    }
    }

    CComPtr<IUIAutomationTextRangeArray> textRangeArray;
    hr = textPattern->GetSelection(&textRangeArray);
    if (FAILED(hr) || !textRangeArray) {
    return hr;
    }

    int length = 0;
    hr = textRangeArray->get_Length(&length);
    if (FAILED(hr) || length == 0) {
    return hr;
    }

    selectedText.clear();
    for (int i = 0; i < length; i++) {
    CComPtr<IUIAutomationTextRange> textRange;
    hr = textRangeArray->GetElement(i, &textRange);
    if (SUCCEEDED(hr) && textRange) {
    BSTR text = nullptr;
    hr = textRange->GetText(-1, &text);
    if (SUCCEEDED(hr) && text) {
    selectedText += text;
    SysFreeString(text);
    }
    }
    }
    return S_OK;
    }

    void MonitorSelectedText(IUIAutomation* automation) {
    while (true) {
    std::wstring currentSelectedText;
    HRESULT hr = GetTextFromActiveWindow(automation, currentSelectedText);

    if (SUCCEEDED(hr) && !currentSelectedText.empty() && currentSelectedText != lastSelectedText) {
    lastSelectedText = currentSelectedText;

    HWND foregroundWindow = GetForegroundWindow();
    wchar_t windowTitle[256];
    GetWindowTextW(foregroundWindow, windowTitle, 256);

    std::wcout << L"\n=== 检测到新的选中文本 ===" << std::endl;
    std::wcout << L"窗口: " << windowTitle << std::endl;
    std::wcout << L"选中内容: " << currentSelectedText << std::endl;
    std::wcout << L"========================\n" << std::endl;
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    }
    }

    int main() {
    CoInitializeEx(NULL, COINIT_MULTITHREADED);

    consoleWindow = GetConsoleWindow();

    CComPtr<IUIAutomation> automation;
    HRESULT hr = CoCreateInstance(CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&automation));

    if (FAILED(hr)) {
    std::wcout << L"无法创建 UI Automation 对象" << std::endl;
    CoUninitialize();
    return -1;
    }

    std::wcout << L"文本选择监控程序已启动..." << std::endl;
    std::wcout << L"程序将在后台监控其他窗口中的文本选择" << std::endl;
    std::wcout << L"按 Ctrl+C 退出程序\n" << std::endl;

    std::thread monitorThread(MonitorSelectedText, automation.p);
    monitorThread.detach();

    std::wcin.get();

    CoUninitialize();
    return 0;
    }

    ```
    spritecn
        8
    spritecn  
       1 小时 42 分钟前
    太久不折腾 win 编辑了,记忆中 ahk/au3 带的工具不错
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5213 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 08:28 · PVG 16:28 · LAX 01:28 · JFK 04:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.