句柄:
句柄是Windows系统中对象或实例的标识,这些对象包括模块、应用程序实例、窗口、控制、位图、GDI对象、资源、文件等 。
从数据类型上来看,它只是一个16位的无符号整数。应用程序总是通过调用Windows API获得一个句柄,之后其他 Windows函数就可以使用该句柄,以引用和操作相应的内核对象。句柄可以像指针那样置空,那样句柄就没有任何意义,不代表任何内核对象 。
句柄地址(稳定)→记载着对象在内存中的地址→对象在内存中的地址(不稳定)→实际对象
句柄是一种指向指针的指针。在Windows中,句柄是一个系统内部数据结构的引用。
1、FindWindow函数
该函数可以通过窗口类名或者窗口标题名来查找特定窗口句柄,返回值是窗口的句柄。
HWND FindWindowW(
[in, optional] LPCWSTR lpClassName,
[in, optional] LPCWSTR lpWindowName
);
lpClassName: "lp"可以当作指针,"ClassName" 为类名。
lpWindowName:前面"lp"一样,"WindowsName"为窗口标题。
LPCWSTR:是一个指向unicode编码字符串的32位指针,wchar型,而不是char型
其相当于WCHAR*,wchar数据类型一般为16或32位,wchar_t所能表示的字符数远超char型。
这里可以用SPY++抓类名/窗口标题。
抓目标窗口,这里就复制标题来抓句柄。
2、SendMessage函数
这个函数的功能是向句柄对应窗口发送指令
SendMessage function (winuser.h) - Win32 apps | Microsoft Docs
LRESULT SendMessage(
[in] HWND hWnd,
[in] UINT Msg,
[in] WPARAM wParam,
[in] LPARAM lParam
);
HWND 窗口句柄
UINT 消息名称
关于消息的文档看这About Messages and Message Queues
文档里可以查到所有消息类型,常用的像是WM前缀下的窗口消息,剪贴板消息等
WPARAM 消息附带内容
LPARAM 消息附带内容
一个是WORD类型的16位整型变量;另一个是LONG类型的32位整型变量。因此根据匈牙利命名法,16位的变量就被命名为wParam, 32位的变量就被命名为lParam。
消息响应机制
消息的组成:一个消息由一个消息名称(UINT),和两个参数(WPARAM,LPARAM)组成。当用户进行了输入或是窗口的状态发生改变时系统都会发送消息到某一个窗口。例如当菜单选中之后会有WM_COMMAND消息发送,WPARAM的低字中(LOWORD(wParam))是命令的ID号,对菜单来讲就是菜单ID。当然用户也可以定义自己的消息名称,也可以利用自定义消息来发送通知和传送数据。
Message.LParam Property (System.Windows.Forms) | Microsoft Docs
UNI 例子1- WM_CLOSE
WM_CLOSE message (Winuser.h) - Win32 apps | Microsoft Docs
LRESULT CALLBACK WindowProc( __in HWND hWindow, __in UINT uMsg, __in WPARAM wParam, __in LPARAM lParam) { switch (uMsg) { case WM_CLOSE: DestroyWindow(hWindow); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWindow, uMsg, wParam, lParam); } return 0; }
By default, the DefWindowProc function calls the DestroyWindow function to destroy the window.
这里说明传入UNI类型数据的值为WM-CLOSE时 会通过DestroyWindow这个函数来摧毁当前窗口,DestroyWindow的如何实现,好奇的话可以点进去看看。
代码
//摧毁窗口测试
void testHWND() {
HWND window; //定义一个窗口句柄变量,用来储存窗口句柄
window = FindWindow(NULL, TEXT("文件资源管理器"));
SendMessage(window, WM_CLOSE, 0, 0);//不需要附带内容
}
打开一枚窗口
运行,发现窗口君他消失了
UNI 例子2- WM_SETTEXT
官方文档,定义,评论
The DefWindowProc function sets and displays the window text. For an edit control, the text is the contents of the edit control. For a combo box, the text is the contents of the edit-control portion of the combo box. For a button, the text is the button name. For other windows, the text is the window title.
简单来说就是,根据物件的不同改不同的名字,按钮改按钮的名字,窗口就改标题。
WM_SETTEXT message (Winuser.h) - Win32 apps | Microsoft Docs
试着写个代码改标题,结果成功了
//设置改标题
void testHWND2() {
HWND window; //定义一个窗口句柄变量,用来储存窗口句柄
window = FindWindow(NULL, TEXT("文件资源管理器"));
SendMessage(window, WM_SETTEXT, 0, LPARAM(TEXT("喷3快来 我tm社保")));//属于long parameter的类型?我也不懂
}
这里遇到2个问题:
1.没法直接把字符串变成LPARAM类型传进去。但用LPARAM(" ")的形式可以传进去,推测是转型成了LPARAM类型。
2.字符串不作处理会出现乱码(估计C++会,而C不会),字符串前加TEXT可以转成unicode字符串就没有乱码了。
执行后
UNI 例子3-WM_CHAR
文档WM_CHAR message (Winuser.h) - Win32 apps | Microsoft Docs
Parameters
wParam
The character code of the key.
用这个参数就完事了
The WM_UNICHAR message is similar to WM_CHAR, but it uses Unicode Transformation Format (UTF)-32, whereas WM_CHAR uses UTF-16.
这里提到UNICHAR可以使用更高字节数32位,但WM_CHAR可以使用16位的unicode字符,其实就已经可以使用中文了,足矣。
可以写个往QQ窗口写入信息,回车模拟发送的程序。
//发送
void sendKey() {
HWND window; //定义一个窗口句柄变量,用来储存窗口句柄
window = FindWindow(NULL, TEXT("XXX")); //根据需要抓窗口
//英文
string str1 = "This is automatic English sentence.";
for (char c : str1)
SendMessage(window, WM_CHAR, WPARAM(c), NULL);//英文用char遍历
//中文
wchar_t str2[] = L"这是代码执行的中文自动消息";//string 改成wchar_t 数组成功了
for(wchar_t c:str2)
SendMessage(window, WM_CHAR, WPARAM(c),NULL);//中文用unicode/wchar_t遍历
//回车发送
SendMessage(window, WM_KEYDOWN, VK_RETURN, NULL);
}
问题:用中文的时候用char遍历会乱码,要改成:wchar_t来获取中文字符。