借助Spy++向指定的窗口发送消息—2
前一部分,我已经完成了程序的基本框架,首先通过SPY查找到主窗体的主标题,然后在程序中根据主标题找到翻译软件的窗口指针,然后根据主窗口指针来枚举所有的子窗口(包括子窗口的子窗口);
在枚举子窗口的过程中,每找到一个子窗口,系统会调用 EnumProc函数来做相应的处理。
下面我要在 EnumProc函数中做些“动作”。
系统每找到一个子窗口就会进入 EnumProc函数,当然也包括找到我们的单词输入窗口,所以我现在要想办法确定 进入EnumProc时的子窗口是不是单词输入窗口。
使用spy窗口查找功能(CTRl+F),把瞄准器拖到单词输入窗口,然后释放瞄准器,这样就可以获得单词输入窗口的相关信息。
上面的图显示了,单词输入窗口的句柄和单词输入窗口的类型(Edit),这里单词输入窗口的标题是空的,因为我们的单词输入窗口没有任何单词。点查找窗口上的确定按钮,看下详细属性。
可以看到这里显示了单词输入窗口的详细信息,其中我们要用到的是“控件ID”,这个数据是单词输入窗口的ID号,这个编号
是永远不会改变的,你可以试试把翻译软件关闭后,再次打开翻译软件,然后定位到单词输入窗口看看他的ID号,就知道了。
(注:这个软件输入框的id号是不变的,但是我试验了下.net平台下的winform程序,发现控件ID却是变化的,我不知道为什么,对于那样的情况,我用的是根据控件在spy++中的相对主窗口的“位置”来确定子窗口的,这个以后再说吧。目前对于这个翻译软件,他的输入框id在每次启动程序后都是不会改变的,所以我可以根据ID来定位单词输入框。为了确定控件的ID是否每次都会改变,所以还是多开启关闭程序几次,看看控件ID是否变化来选择定位方法)
这里可以点击下同步按钮,这样在spy主窗口中,会定位到单词输入窗口。
可以看到spy主窗口中对应的单词输入框窗口被选中了,他的句柄和我们先前在查找窗口中看到的句柄一致。不过我们可以看到在这个窗口的父窗口上“窗口 00010918"Lingoes 灵格斯"Afx:400000:0”这里的主窗口句柄是00010918,和我在第一部分查找翻译软件主窗口看到的句柄值不同。这是因为那篇文章是前天写的,今天我重新开机启动了翻译软件,所以句柄也就是系统分配的“编号”不一样了,这也说明了,句柄在两次启动中可能是不同的,呵呵....;
知道了确定子窗口的方法,下面我就在EnumProc函数中来判断当前的窗体的控件id是否和我用spy++看到的单词输入框控件ID相同。
1.
2. BOOL CALLBACK EnumProc(HWND hwnd,LPARAM lParam)
3. {
4. int id=-1;
5.
6. //获得当前这个子窗口的ID
7. id=::GetDlgCtrlID(hwnd);
8.
9. //判断id是否和我用spy++看到的单词输入框ID相等,如果相等当前的hwnd就是
10. //单词输入框的句柄
11. if(id==0x69) //SPY++中空间ID是16进制的
12. {
13. //向单词输入窗口中发送WM_SETTEXT消息,LPARAM参数是要发送的文本
14. //这里我发送的是单词spy
15. ::SendMessage(hwnd,WM_SETTEXT,NULL,(LPARAM)("spy"));
16. }
17.
18. return TRUE;
19. }
20.
这里用到了SDK下的SendMessage函数。MSDN中该函数的说明如下:
LRESULT SendMessage(
HWNDhWnd, // handle to destination window
UINT Msg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
Parameters
hWnd
//指向了将要接受该消息的窗口,即发送的的目标窗口,这里就是我们的单词输入窗口。 [in] Handle to the window whose window procedure will receive the message. If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows. Msg
//将要发送的消息 [in] Specifies the message to be sent. wParam
//该消息的附加参数,不同的消息有不同的含义 [in] Specifies additional message-specific information. lParam
//该消息的附加参数,不同的消息有不同的含义
[in] Specifies additional message-specific information.
这里我使用了一个消息WM_SETTEXT,MSDN中该消息的说明如下:
WM_SETTEXT
//一个应用程序通过发送WM_SETTEXT消息来设置窗口的文本,发送消息可以使用SendMessage,具体参数如下:
An application sends a WM_SETTEXT message to set the text of a window.
To send this message, call the SendMessage function with the following parameters.
SendMessage(
(HWND) hWnd, // handle to destination window
WM_SETTEXT, // message to send
(WPARAM) wParam, // not used; must be zero
(LPARAM) lParam
Parameters
wParam
//这个参数不被使用
This parameter is not used.
lParam
//这个参数用来指向一个字符串,即将要设置的窗口文本字符串,这里要注意参数类型要匹配。
Pointer to a null-terminated string that is the window text.
这样就完成了向指定窗口发送单词文本的功能。
按照我们正常的操作顺序,输入完单词后应该按一下回车或翻译软件上的“——>”按钮来确认我们的输入,上面只是实现了向单词输入框中输入单词的功能,并没有点击确定按钮或回车,之所以会显示出该单词的中文翻译,是因为这个软件在输入单词后会自动的在本地字库中自动查询。如果我们点击确定按钮就可以在本地和网络上查找该单词的中文翻译。下一步就实现确认输入的功能。