我有与某些测量设备接口的软件( Altair )。该软件的一组有限的功能作为API公开,制造商以其MATLAB实现的形式提供给我(没有额外的文档)。根据提供的来源,我知道与此应用程序的所有通信都使用Kernel32.dll
或user32.dll
(Windows API库),更具体地说,使用以下方法:
user32
)user32
)user32
)Kernel32
)我在API中缺少的一个功能是能够检索隐藏在此软件某处的某个文本设置。幸运的是,该设置显示在其UI中的TextBox
(带有不可选文本)内。
我的目标是在MATLAB中获得一个出现在这个单独的非MATLAB窗口内的字符串。
快速互联网搜索显示 1,2 ,如果{{1}, 实际上可以通过Windows API实现可以为包含所需HWND
的特定控件(或"窗口")获取(Handle to Window)。然后将WM_GETTEXT
发送到控件,理论上返回该字符串。
我采取的第一步是检查String
是否可以获得。这是使用Microsoft Spy++ utility完成的(VS2015可选)。结果如下:
上述层次结构意味着1 <3> rd HWND
的类child
的4 th Static
窗口的&gt; st child
.....&#34; Altair&#34;是我正在寻找的。 p>
就Windows API而言,这些方法对于遍历窗口层次结构和获取字符串非常有用:
通过将句柄依次传递给应用程序定义的回调函数,枚举属于指定父窗口的子窗口。 EnumChildWindows 继续,直到枚举最后一个子窗口或回调函数返回 FALSE 。
不幸的是,这是不可用的,因为&#34; MATLAB共享库接口不支持带有函数指针输入的库函数。&#34; (from the docs of loadlibrary
),恰好是child
的强制性输入。
检索顶级窗口的句柄,该窗口的类名和窗口名与指定的字符串匹配。此功能不搜索子窗口。此功能不执行区分大小写的搜索。
要搜索子窗口,请从指定的子窗口开始,使用FindWindowEx函数。
GetWindowText
:
将指定窗口标题栏的文本(如果有的话)复制到缓冲区中。如果指定的窗口是控件,则复制控件的文本。但是, GetWindowText 无法检索其他应用程序中控件的文本。
SendMessage
:
将指定的消息发送到一个或多个窗口。 SendMessage 函数调用指定窗口的窗口过程,并且在窗口过程处理完消息之前不会返回。
所以我开始创建一个EnumChildWindows
头文件,该文件将与MATLAB loadlibrary
一起使用,我最终得到了以下内容(c
):
graphic_hack.h
以上是手动替代建议here的值得注意的方法,它使用以下方法生成所有可用API方法的标头:
// 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);
下面给出了获得控件[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');
的MATLAB代码:
HWND
最后一步,我正在努力,它发送WM_GETTEXT
,这将得到我的字符串。具体来说,问题,我理解的方式,与SendMessage的输入参数的定义有关:
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
wParam [in]
输入:WPARAM
其他特定于消息的信息。
lParam [in]
输入:LPARAM
其他特定于消息的信息。
如果WM_GETTEXT
是:
的wParam
要复制的最大字符数,包括终止空字符。
由于从ANSI到Unicode的转换,ANSI应用程序可能会使缓冲区中的字符串大小减小(至少为wParam值的一半)。
lParam的
指向要接收文本的缓冲区的指针。
这给了我一个问题:一方面我应该传递一个LRESULT WINAPI SendMessage(
_In_ HWND hWnd,
_In_ UINT Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
,根据头文件中的LPARAMS
是typedef
(这意味着MATLAB)期望一个数字输入),但它需要是指向&#34;文本缓冲区的指针&#34;,这意味着我应该传递像libpointer('String')
这样的东西。
碰巧,其他人在过去遇到了相关问题,并it was suggested使用了所谓的MAKELPARAM
macro定义为:
long
...以便从其他类型的输入中创建正确的#define MAKELPARAM(l, h) ((LPARAM) MAKELONG(l, h))
。不幸的是,我发现这对我没有任何帮助。
这可能是我在如何在MATLAB 3,4 中正确使用指针或我遇到的MATLAB限制的误解。无论哪种方式,我问我如何从MATLAB 调用LPARAMS
?
答案 0 :(得分:7)
MATLAB的External Functions interface允许以各种语言调用函数,其中包括Java。正如this answer中所提到的,与Windows API接口的流行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。强>