[ - 介绍 - ]
我有与一些测量设备接口(interface)的软件 ( Altair )。该软件的一组有限功能作为 API 公开,由制造商以其 MATLAB 实现的形式提供给我(没有额外的文档)。根据提供的来源,我知道与此应用程序的所有通信都使用 Kernel32.dll
或 user32.dll
( Windows API 库),更具体地说是以下方法:
user32
) user32
) user32
) Kernel32
) 我在 API 中缺少的功能之一是能够检索隐藏在该软件某处的特定文本设置。幸运的是,该设置出现在
TextBox
中。 (带有不可选择的文本)在其 UI 中。我的目标是在 MATLAB 中获得出现在这个单独的非 MATLAB 窗口中的字符串 .
[ - 我的尝试 - ]
快速互联网搜索发现 1 , 2如果
HWND
,这实际上是可能的,通过Windows API (窗口句柄)可以为持有所需的特定控件(或“窗口”)获取String
. WM_GETTEXT
然后发送到控件,理论上返回字符串。我采取的第一步是检查
HWND
甚至可以获得。这是使用 Microsoft Spy++ utility 完成的(可选地与 VS2015 一起使用)。结果如下:上面的层次结构意味着第 4 个
child
类(class)Static
第三期 child
第一期 child
..... 窗口“Altair”就是我要找的。就 Windows API 而言,这些方法对于遍历窗口层次结构和获取字符串似乎很有用:
EnumChildWindows
:Enumerates the child windows that belong to the specified parent window by passing the handle to each child window, in turn, to an application-defined callback function. EnumChildWindows continues until the last child window is enumerated or the callback function returns FALSE.
然而不幸的是,这是无法使用的,因为“MATLAB 共享库接口(interface)不支持具有函数指针输入的库函数”。 ( from the docs of
loadlibrary
),恰好是 EnumChildWindows
的强制性输入. FindWindow
和 FindWindowEx
:Retrieves a handle to the top-level window whose class name and window name match the specified strings. This function does not search child windows. This function does not perform a case-sensitive search.
To search child windows, beginning with a specified child window, use the FindWindowEx function.
GetWindowText
:Copies the text of the specified window's title bar (if it has one) into a buffer. If the specified window is a control, the text of the control is copied. However, GetWindowText cannot retrieve the text of a control in another application.
SendMessage
:Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
所以我开始创建一个
c
将与 MATLAB 的 loadlibrary
一起使用的头文件,我得到了以下结果(graphic_hack.h
😉):// Windows Data Types:
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx
typedef unsigned int UINT;
typedef UINT WPARAM;
typedef long LPARAM;
typedef long LRESULT;
typedef unsigned long HANDLE;
typedef unsigned long HWND;
typedef unsigned long HICON;
typedef unsigned long HINSTANCE;
typedef int BOOL;
typedef const char *LPCSTR;
typedef char *LPSTR;
typedef char TCHAR;
typedef LPCSTR LPCTSTR;
typedef LPSTR LPTSTR;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;
typedef unsigned long ULONG;
#define STDCALL __stdcall
#define CALLBACK __stdcall
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms633499%28v=vs.85%29.aspx
HWND STDCALL FindWindowA(LPCTSTR,LPCTSTR);
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms633500%28v=vs.85%29.aspx
HWND STDCALL FindWindowExA(HWND,HWND,LPCTSTR,LPCTSTR);
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms633520%28v=vs.85%29.aspx
int STDCALL GetWindowTextA(HWND,LPTSTR,int);
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms644950%28v=vs.85%29.aspx
LRESULT STDCALL SendMessageA(HWND,UINT,WPARAM,LPARAM);
以上是建议的值得注意的方法的手动替代here ,它使用以下内容为所有可用的 API 方法生成 header :
[nf,warn] = loadlibrary('user32.dll',...
'C:\Program Files (x86)\Windows Kits\8.1\Include\um\windows.h',...
'alias','user','includepath','C:\Program Files (x86)\Windows Kits\8.1\Include\um\',...
'includepath','C:\Program Files (x86)\Windows Kits\8.1\Include\shared\',...
'addheader','WinUser','mfilename','user_header');
使我获得
HWND
的 MATLAB 代码控制的内容如下:if (libisloaded('gh'))
unloadlibrary('gh')
end
[~,~]=loadlibrary('user32.dll', 'graphic_hack.h','alias','gh');
javaaddpath(fullfile(pwd,'User32Util.jar'));
%Debug: libfunctionsview gh;
% libfunctions('gh','-full');
%% Obtain the Altair field handle using various trickery:
hwndAltair = calllib('gh','FindWindowA','Altair',[]); %Find the Altair Window
hTmp(1) = calllib('gh','FindWindowExA',hwndAltair,0,'AfxControlBar70','Capture Manager');
hTmp(2) = calllib('gh','FindWindowExA',hTmp(1),0,'Afx:00400000:48:00000000:01100078:00000000',[]);
hTmp(3) = calllib('gh','FindWindowExA',hTmp(2),0,'SysTabControl32',[]);
hTmp(4) = calllib('gh','FindWindowExA',hTmp(3),0,[],'');
hTmp(5) = calllib('gh','FindWindowExA',hTmp(4),0,'Static',[]);
for k = 1:4
hTmp(5) = calllib('gh','FindWindowExA',hTmp(4),hTmp(5),'Static',[]);
end
[ - 实际问题 - ]
我正在努力的最后一步,它调度了
WM_GETTEXT
那会让我得到字符串。具体来说,我理解的问题与 SendMessage 的输入参数的定义有关。 :LRESULT WINAPI SendMessage(
_In_ HWND hWnd,
_In_ UINT Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
wParam [in]
Type: WPARAM
Additional message-specific information.
lParam [in]
Type: LPARAM
Additional message-specific information.
在
WM_GETTEXT
的情况下是:wParam
The maximum number of characters to be copied, including the terminating null character.
ANSI applications may have the string in the buffer reduced in size (to a minimum of half that of the wParam value) due to conversion from ANSI to Unicode.
lParam
A pointer to the buffer that is to receive the text.
这给我带来了一个问题:一方面我应该通过
LPARAMS
,根据 typedef
在头文件中是一个 long
(这意味着 MATLAB 需要一个数字输入),但它需要是一个指向“文本缓冲区”的指针,这意味着我可能应该传入类似 libpointer('String')
的内容。 .碰巧,其他人过去也遇到过相关问题,it was suggested雇用所谓的
MAKELPARAM
macro定义为:#define MAKELPARAM(l, h) ((LPARAM) MAKELONG(l, h))
...为了创建正确的
LPARAMS
来自另一种类型的输入。不幸的是,我发现这无法帮助我。这可能是我对如何在 MATLAB 中正确使用指针的误解 3 , 4 ,或者我遇到的 MATLAB 的限制。无论哪种方式,我问我如何继续拨打
SendMessage
来自 MATLAB ?
最佳答案
MATLAB 的 External Functions interface允许调用各种语言的函数,其中包括Java。如 this answer 中所述,与 Windows API 接口(interface)的流行 Java 库是 Java Native Access (JNA) .
在 this answer 中演示如何利用 JNA 发送 WM_GETTEXT
信息。针对这个问题的具体需求,改编成static
方法,所需的Java-JNA代码如下所示:
package hack.graphic.devil
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.win32.StdCallLibrary;
public class User32Util {
interface User32 extends StdCallLibrary {
User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
int WM_GETTEXT = 0x000D;
LRESULT SendMessageA(HWND editHwnd, int wmGettext, long l, byte[] lParamStr);
}
public static String getStringFromHexHWND(String args0) {
User32 user32 = User32.INSTANCE;
HWND target = new HWND(new Pointer(Long.decode(args0)));
byte[] lParamStr = new byte[512];
user32.SendMessageA(target, User32.WM_GETTEXT, 512, lParamStr);
return Native.toString(lParamStr);
}
}
上面的代码导入在 an older branch of JNA 中找到的类(具体来说, its
/src/com/sun/jna/
folder )。后 packaging as a .jar
,然后可以使用以下方法从 MATLAB 中调用它:javaaddpath(fullfile(pwd,'User32Util.jar'));
...
str = char(hack.graphic.devil.User32Util.getStringFromHexHWND(['0x' dec2hex(hTmp(5))]));
str
然后将包含所需的 String
. Q.E.F.
关于matlab - 使用 MATLAB 从另一个应用程序中的控件获取文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34398149/