分享

借助Spy++向指定的窗口发送消息

 长江黄鹤 2017-06-10

先说说俺做这个工作的背景吧:

        我想找一个单词数据库,里面有每个单词对应的中文翻译,但是网上找了好久没有找到,不知道是不是自己输入的关键词不对。实在没有办法就想自己生成一个单词数据库。如果要自己生成一个单词库,首先就是翻译的问题。首先要找到常用单词表,这个很简单。关键是把单词表中的每个单词翻译成中文。我肯定不能够手动去录入每个单词的中文意思,所以就想借助翻译软件来自动的完成单词翻译成中文这个过程。这样的话,我就需要向翻译软件发送消息来自动的输入单词和查询单词。这里面最头痛的问题就是“向翻译软件的指定窗口发送消息”,网上找了很多资料,都很零散,学习过程中很吃力,自己摸索了一段时间,基本上解决了这个问题,回头想想觉得有必要整理一下,方便自己也方便他人。(注:我水平一般,文中如有错误请指正,谢谢!)

 

1.翻译软件(Lingoes 灵格斯)

 

2.找到上图的文本框(a那个位置),那是我们输入单词的地方,所以我们的输入单词的消息要发送到该窗口(文本框也是个窗口)

首先启动spy++,我用的是vs2005自带的spy++ 8.0,如图所示

 

 

启动spy以后,点击工具栏上的第5个按钮,那个“窗口望远镜”图标,或者直接按Ctrl+F,打开一个查找窗口界面

 

 

查找窗口中的那个瞄准器图标是可以拖动的,把这个图标拖动到我们的翻译软件界面的外框上然后释放瞄准器,可以看到如下信息

 

 

如图所示:翻译软件的大窗口已被spy选中,在查找窗口中显示了翻译软件的相关信息。这里对我们有用的是“标题”。点击“确定”可以看到更详细的属性信息。这里瞄准主窗口主要是获得“标题”信息,所以没有必要查看详细信息了。在后面寻找输入窗口(a字符窗口)的时候需要用到详细信息。这里之所以要获得翻译软件的标题是因为我们要调用API来寻找到这个主窗口,找到主窗口后,我们就可以寻找主窗口下的子窗口,即我们要找的单词输入框(a位置);由于一个软件的标题通常是不会变的,所以我选择了通过标题寻找到主窗口。画面上标题上方还有一个句柄值,这个只是我们翻译软件运行后,系统为他分配的一个“编号”,这个编号在翻译软件运行的过程中是不会改变的,但是如果你关闭翻译软件后重新再次运行翻译软件,系统分配给翻译软件的这个编号可能就和先前一次分配的编号不同了,这个很好理解,就像我们的ADSL上网。我们使用网络的时候,服务商会提供给我们一个IP,我们不使用网络了,这个ip可能又被服务商分配给其他人用了。下次我们再次使用网络的时候,服务商会再给我们分配一个IP,但是这个ip和先前的上网IP是否一样就说不好了,可能一样,也可能不一样。

 

下面是我根据标题寻找到翻译软件主窗口的代码:(VC++2005 MFC)

 

 

 

  1. /*列举子窗口时每找到一个子窗口系统会调用这个函数,hwnd是子窗口的句柄,lParam是我们在调用EnumChildWindows时传递的值*/
  2. BOOL CALLBACK EnumProc(HWND hwnd,LPARAM lParam)
  3. {
  4.     
  5.     return TRUE;
  6. }
  7. /*对话框程序上有一个按钮,点击按钮开始寻找主窗口,并查询主窗口下的所有子窗口。*/
  8. void CspyDlg::OnBnClickedButton1()
  9. {
  10.     // 寻找标题为“Lingoes 灵格斯”的窗口指针 
  11.     CWnd *w=FindWindow(NULL,"Lingoes 灵格斯");
  12.     //parent就是该主窗口的句柄,转换成16进制就等于上图0004092E
  13.      HWND parent=w->m_hWnd;
  14.     //列举主窗口下的所有子窗口,包括子窗口的子窗口 
  15.     EnumChildWindows(parent,EnumProc,(LPARAM)this); 
  16.     
  17. }

这里主要用到了两个MFC API函数:FindWindow 和 EnumChildWindows

这里把MSDN上FindWindow 的信息找出来如下:

static CWnd* PASCAL FindWindow(
   LPCTSTR lpszClassName,
   LPCTSTR lpszWindowName 
);

Parameters

lpszClassName  //WNDCLASS结构体指针,如果这个参数为NULL,则所有的都匹配;(呵呵,英语很烂啊)

Points to a null-terminated string that specifies the window's class name (a WNDCLASS structure). If lpClassName is NULL, all class names match.

 

lpszWindowName  //窗口名称,如果为NULL,所有都匹配;(这就是我们用到的一个参数)

Points to a null-terminated string that specifies the window name (the window's title). If lpWindowName is NULL, all window names match.

 Return Value  //返回值为NULL,则没有找到指定的窗口

Identifies the window that has the specified class name and window name. It is NULL if no such window is found.

 

 

在寻找主窗口的代码最后,我调用了EnumChildWindows(parent,EnumProc,(LPARAM)this); 来枚举主窗口下的所有子窗口。

MSDN中该函数说明如下:

 

BOOL EnumChildWindows(      
    HWND hWndParent,     WNDENUMPROC lpEnumFunc,     LPARAM lParam );

Parameters

 

                hWndParent  //父窗口句柄,就是我们找到的parent

                [in] Handle to the parent window whose child windows are to be enumerated. If this parameter is NULL, this function     is equivalent to EnumWindows. Windows 95/98/Me: hWndParent cannot be NULL.

 

lpEnumFunc //回调函数指针,每找到一个子窗口系统就会调用这个函数来做相应的处理,这个函数需要自己写。
                     // 具体这个函数的格式,可以看   EnumChildProc 这里我们自己写的函数名称是  EnumProc,代码最 上面就是。
[in] Pointer to an application-defined callback function. For more information, see EnumChildProc.

 

lParam  //我们自己传递一个附加参数,这里我们传递一个窗口指针过去
[in] Specifies an application-defined value to be passed to the callback function.

 

 

 

 

 

 

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多