从另一个应用程序窗口中的文本字段读取

Posted

技术标签:

【中文标题】从另一个应用程序窗口中的文本字段读取【英文标题】:Reading from a text field in another application's window 【发布时间】:2010-09-26 00:26:51 【问题描述】:

有没有办法让 Windows 应用程序访问另一个应用程序的数据,更具体地说是 GUI 中的文本输入字段,并在那里获取文本以便在我们自己的应用程序中进行处理?

如果可能的话,有没有办法“屏蔽”你的应用程序来防止它?

编辑:前三个答案似乎是关于获取另一个应用程序窗口标题,而不是该窗口中的特定文本输入字段。

我不是 Windows API 期望的,所以您能否更准确地说我如何在该窗口中找到某个文本字段,它的先决条件是什么(好像知道窗口句柄是必需的,是否需要知道文本字段句柄也是如此?我如何得到它?等等...)

C++ 中的代码 sn-ps 真的很感激。 MSDN 帮助很难浏览,因为 Win32-API 有如此可怕的命名约定。

已完成!请参阅下面的答案,了解 C++ 的操作方法。

【问题讨论】:

【参考方案1】:

为了从另一个应用程序的文本框中读取文本内容,您需要以某种方式获取该文本框控件的窗口句柄。根据您的应用程序 UI 的设计方式(如果它有 UI),您可以使用几种不同的方法来获取此句柄。您可以使用“FindWindow”/“FindWindowEx”来定位您的控件,或者在有意义的情况下使用“WindowFromPoint”。无论哪种方式,一旦你有了文本控件的句柄,你就可以向它发送一个“WM_GETTEXT”消息来检索它的内容(假设它是一个标准的文本框控件)。这是一个编造的样本(没有错误检查):

HWND hwnd = (HWND)0x00310E3A;
char szBuf[2048];
LONG lResult;

lResult = SendMessage( hwnd, WM_GETTEXT, sizeof( szBuf ) / sizeof( szBuf[0] ), (LPARAM)szBuf );
printf( "Copied %d characters.  Contents: %s\n", lResult, szBuf );

我使用“Spy++”来获取一个文本框窗口的句柄。

至于保护您自己的文本框不被这样检查,您总是可以对您的文本框进行子类化(请参阅“SetWindowLong”和“GWL_WNDPROC”以获得“nIndex”参数)并对“WM_GETTEXT”进行一些特殊处理" 消息以确保仅处理来自同一进程的请求。

【讨论】:

【参考方案2】:

好的,我有点想通了。

现在的起点是准确地知道窗口句柄,我们只知道部分窗口标题,所以首先要做的是找到那个主窗口:

...
EnumWindows((WNDENUMPROC)on_enumwindow_cb, 0);
...

枚举桌面上的所有窗口。它使用这些窗口句柄中的每一个进行回调:

BOOL CALLBACK on_enumwindow_cb(HWND hwndWindow, LPARAM lParam) 
    TCHAR wsTitle[2048];
    LRESULT result;
result = SendMessage(hwndWindow, WM_GETTEXT, (WPARAM) 2048, (LPARAM) wsTitle);
    ...

通过使用 wsTitle 和 little regex 魔法,我们可以找到我们想要的窗口。

通过使用前面提到的 Spy++,我可以找出文本编辑字段类名并使用它在 hwndWindow 中找到想要的字段:

hwndEdit = FindWindowEx(hwndWindow, NULL, L"RichEdit20W", NULL);

然后我们可以从该字段中读取文本:

result = SendMessage(hwndEdit, WM_GETTEXT, (WPARAM) 4096, (LPARAM) wsText);

我希望这可以帮助任何遇到同样问题的人!

【讨论】:

什么是wsText?你能发布你的来源吗?谢谢。 是chararray,同回调代码中的TCHAR wsTitle[2048];。源已经丢失,抱歉。【参考方案3】:

看看AutoHotkey。如果您的应用程序需要 API,请查看其来源。 为防止这种情况,请使用自定义小部件而不是 WinForms、MFC 或 Win32 API。这不是万无一失的,但会有所帮助。

【讨论】:

我不知道在源代码中搜索什么,给我指点?【参考方案4】:

是的,有很多方法可以实现(一种方法是使用 WINAPI GetWindow 和 GetWindowText)。

首先,获取要从中检索文本的文本框的句柄(使用 FindWindow、EnumChildWindows 和其他 API),然后:

旧VB6-codeexample,API声明:

Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long  
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long  

提取文本的代码:

Dim MyStr As String
MyStr = String(GetWindowTextLength(TextBoxHandle) + 1, Chr$(0))
GetWindowText TextBoxHandle, MyStr, Len(MyStr)
MsgBox MyStr

【讨论】:

【参考方案5】:

关于如何屏蔽应用程序以防止它,您可以做很多事情。 一种方法是拥有一个自己的控件来处理文本输入,该控件从假设放置文本的几个标签构建文本,或者以图形方式绘制文本。

【讨论】:

【参考方案6】:

您也可以使用 EM_GETTEXTRANGE 消息从 Richedit 控件中获取文本,但它仅适用于创建控件的同一进程。

【讨论】:

不幸的是,它在这种情况下不可用,因为关键是要访问另一个进程 UI。

以上是关于从另一个应用程序窗口中的文本字段读取的主要内容,如果未能解决你的问题,请参考以下文章

如何从另一种方法访问 tableviewCell 中的文本字段

从另一个窗口访问和更改 WPF 中的控件

无法从另一个应用程序的面板控件中获取文本

C#窗口应用程序从另一个应用程序的光标位置获取单词

如何从另一个线程更新 GUI 上的文本框 [重复]

Oracle MAF:在 Windows 10 周年版下单击对话框弹出窗口中的输入文本字段导致随机崩溃