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

2 天前
 ck125s

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

若方法有效感谢🙏200RMB

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

现象:

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

问题:

我自己的代码,无论用哪种方式,都检测不到 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

793 次点击
所在节点    C++
10 条回复
dandycheung
2 天前
看你这过程,不像是小白啊。你要是能把你说的那个软件自己编译成功,逐步调试的话,会不会好点?还有就是有没可能是人家的 manifest 里向系统申请了什么权限之类的,而你自己的落下了?好久不玩 Windows 编程了, 纯属瞎蒙啊。主要是拒绝 0 回复……
dereklu4
2 天前
请问是要这种效果吗
![image]( https://imgur.com/a/sP1z8VF)
dereklu4
2 天前
ck125s
2 天前
@dereklu4 是的,方便加你微信咨询吗
ck125s
2 天前
@dandycheung 好的 谢谢老哥
dereklu4
2 天前
maggch97
2 天前


让 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
2 天前
太久不折腾 win 编辑了,记忆中 ahk/au3 带的工具不错
iorilu
2 天前
这个框架能捕获微信内容, 做到自动化操作微信码
ck125s
2 天前
已解决,感谢大家。

结论是这样的,希望能帮助有需要的人:

Interop.UIAutomation 或 C++ COM UIA 的原生方式,无法让传统 Win32 Edit 控件支持 TextPattern ,因为底层的 MSAA/IAccessible 本身并不提供足够的文本访问接口,UIA 也不会自动合成该模式。只有 System.Windows.Automation 这种托管客户端,在其背后的 UIAutomationClientsideProviders.dll 中,才能通过与 MSAA 进行通信,将 Edit 控件“模拟”成支持 TextPattern 的 Document 类型。这个过程本质上是依赖客户端增强( Proxy ),而并非 Edit 控件原生能力。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1157005

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX