酷儿 发表于 2008-5-3 15:33:11

转帖Autoit系统消息详解——GUI通知

Autoit系统消息详解——GUI通知2007-05-26 19:07很多人都对系统消息比较陌生,实际上,Autoit里用GUIGetMsg和GUICtrlSetOnEvent函数捕捉的GUI事件都属于系统消息的范畴。而在v3.1.0以后的版本里,我们就可以用GUIRegisterMsg函数来自行捕捉系统消息,藉此来实现对右击、双击、获取焦点等行为的判断。本文将探讨如何在Autoit里捕捉并处理GUI通知。





先看一下下面的例子,这个例子实现了对双击列表框的响应:





CODE: AutoItGUICreate("MyGUI", 359, 94, -1, -1)

$list = GUICtrlCreateListView("ddddddddddd", 10, 10, 320, 80)

Global Const $WM_NOTIFY = 0x004E
GUIRegisterMsg($WM_NOTIFY, "WM_Notify_Events")

GUISetState()
Do
Until GUIGetMsg() = -3

Func WM_Notify_Events($hWndGUI, $MsgID, $wParam, $lParam)
#forceref $hWndGUI, $MsgID, $wParam
Local Const $NM_FIRST = 0
Local Const $NM_DBLCLK = ($NM_FIRST - 3)

Local $tagNMHDR, $event, $hwndFrom, $code
$tagNMHDR = DllStructCreate("int;int;int", $lParam) ;NMHDR (hwndFrom, idFrom, code)
If @error Then Return
$event = DllStructGetData($tagNMHDR, 3)

If $event = $NM_DBLCLK Then MsgBox(0, "", "双击")

$tagNMHDR = 0
$event = 0
$lParam = 0
EndFunc ;==>WM_Notify_Events
下面对整段代码进行分析:


Global Const $WM_NOTIFY = 0x004E

这一句是对系统消息的赋值,和一些高级语言不同,Autoit的库里并不包含系统消息,如果我们想要使用某一消息就必须先对其赋值。

类似的,我们在建立GUI时都会加上一句#include <GUIConstants.au3>,而GUIConstants.au3里就是对GUI样式的赋值。

另外,你可以使用 Win32 API Constants 这个工具来查看不同系统消息的值。


GUIRegisterMsg($WM_NOTIFY, "WM_Notify_Events")

注册WM_NOTIFY这个消息ID(message),每当有新的通知(notification)产生时就会执行WM_Notify_Events这个函数。要捕捉不同的系统通知就需要注册不同的消息ID,类似的消息ID还有WM_COMMAND、WM_COMMNOTIFY等。

注意,我在描述系统消息时都没有加上$号,给变量加$号貌似是Autoit的特色,在后文提到系统消息时我都会省略掉$号。


Func WM_Notify_Events($hWndGUI, $MsgID, $wParam, $lParam)

...

EndFunc ;==>WM_Notify_Events


每当有新的通知产生时这个函数就会被执行,其中$wParam就是发送通知的控件ID,而$event就是被触发的通知。

还有一点很重要,不同的消息ID传递的参数意义也不同,后文会继续提到。


If $event = $NM_DBLCLK Then MsgBox(0, "", "双击")

如果系统通知是双击就弹出对话框,你还可以用$wParam来判断具体控件。

经过上面的阅读相信大家对系统消息处理的基本原理有了了解,下面我们将了解到如何找到并使用我们想要的系统消息。

所有的GUI通知我们都可以在MSDN的控件页面下找到,地址是http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/wincontrols.asp 。

GUI通知分为两类,一类是通用的,一类是专门针对某一种控件的。通用消息可以在旁边侧栏里的General Control Information 下找到,其余的通知直接往下翻,然后点开不同的控件类型就是了。

前文我已说到,不同的系统通知需要注册不同的消息ID,具体的对应关系我们也可以在MSDN上找到。

比如NM_DBLCLK通知,在MSDN上是这样描述的:


Notifies a control's parent window that the user has double-clicked the left mouse button within the control. NM_DBLCLK is sent in the form of a WM_NOTIFY message.

也就是说需要注册WM_NOTIFY这个消息ID。

再如LBN_SETFOCUS通知,我们可以找到这样几句话:


An application sends the LBN_SETFOCUS notification message when a list box receives the keyboard focus. The parent window of the list box receives this notification message through the WM_COMMAND message.

这自然是说需要注册WM_COMMAND这个消息。

最后还剩下一个问题,就是不同的消息ID传递的参数不同,具体信息需要我们在MSDN里搜索。

比如说WM_NOTIFY这个消息,我们搜索到的描述页面是http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/common/messages/wm_notify.asp 。里面有这样的描述:


lResult = SendMessage(            // returns LRESULT in lResult
         (HWND) hWndControl,            // handle to destination control
         (UINT) WM_NOTIFY,            // message ID
         (WPARAM) wParam,            // = (WPARAM) (int) idCtrl;
         (LPARAM) lParam            // = (LPARAM) (LPNMHDR) pnmh;
);

也就是说$wParam变量返回控件ID,而$lParam则包含了我们想要的通知类型。

再往下翻,有这样的话:


pnmh
Pointer to an NMHDR structure that contains the notification code and additional information. For some notification messages, this parameter points to a larger structure that has the NMHDR structure as its first member.

也就是说$lParam这个变量为NMHDR结构,我们这样分解$lParam:


$tagNMHDR = DllStructCreate("int;int;int", $lParam) ;NMHDR (hwndFrom, idFrom, code)
$event = DllStructGetData($tagNMHDR, 3)

这样我们就可以由$event得到具体的通知类型。

另外我们还需要明晰一下概念,像NM_DBLCLK、NM_RCLICK、CBN_SELCHANGE之类的属于通知(notification),而WM_COMMAND、WM_NOTIFY等则属于消息(message)。

再看到下面一个例子:

CODE: AutoItGUICreate("MyGUI", 359, 94, -1, -1)

$list = GUICtrlCreateLabel("ddddddddddd", 10, 10, 320, 80)

Global Const $WM_COMMAND = 0x0111

GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND")

GUISetState()
While 1
    $msg = GUIGetMsg()
    Select
      Case $msg = -3
            ExitLoop
      Case Else
            ;;;
    EndSelect
WEnd

Func MY_WM_COMMAND($hWnd, $msg, $wParam, $lParam)
    Local $nNotifyCode = BitShift($wParam, 16)
    Local $nID = BitAND($wParam, 0xFFFF)
    Local $hCtrl = $lParam
   
    Local Const $STN_DBLCLK = 1
   
    If $nNotifyCode = $STN_DBLCLK Then MsgBox(0, "", "双击")
   
EndFunc   ;==>MY_WM_COMMAND
在这个例子里我想要捕捉文字控件的双击通知,在Static Controls里我得知双击通知是STN_DBLCLK,而我需要注册WM_COMMAND消息。

在WM_COMMAND里我又找到了下面的话:


WM_COMMAND wNotifyCode = HIWORD(wParam);
   wID = LOWORD(wParam);
   hwndCtl = (HWND) lParam;

即$lParam是控件ID,而$wParam包含了通知类型。再看下面的话:


wNotifyCode
Value of the high-order word of wParam. Specifies the notification code if the message is from a control. If the message is from an accelerator, this parameter is 1. If the message is from a menu, this parameter is 0.

可知我们就需要用下面的代码分解$wParam:


Local $nNotifyCode = BitShift($wParam, 16)

这样$nNotifyCode 里就储存了通知类型。

最后我们就用下面的代码来提示双击操作:


If $nNotifyCode = $STN_DBLCLK Then MsgBox(0, "", "双击")

看了上面的例子相信大家已经能够熟练处理GUI通知,最后我再给出一个例子供大家举一反三:

拖动滚动条设置窗口透明度:

CODE: AutoIt$gui = GuiCreate("MyGUI", 392, 86,-1, -1)

$Slider_1 = GuiCtrlCreateSlider(30, 10, 340, 60)
GUICtrlSetLimit ($Slider_1,255)
GUICtrlSetData($Slider_1, 255)

Global Const $WM_HSCROLL = 0x114
Global Const $TB_LINEUP               = 0
Global Const $TB_LINEDOWN               = 1
Global Const $TB_PAGEUP               = 2
Global Const $TB_PAGEDOWN               = 3
Global Const $TB_THUMBPOSITION          = 4
Global Const $TB_THUMBTRACK             = 5

GUIRegisterMsg($WM_HSCROLL, "MY_WM_HSCROLL")

GUISetState()
While 1
    $msg = GUIGetMsg()
    Select
      Case $msg = -3
            ExitLoop
      Case Else
            ;;;
    EndSelect
WEnd

Func MY_WM_HSCROLL($hWnd, $msg, $wParam, $lParam)
    $nScrollCode      = BitAnd($wParam, 0x0000FFFF)
    $nPos         = BitShift($wParam, 16)
    $hwndScrollBar    = $lParam
    Switch $nScrollCode
      Case $TB_LINEDOWN ,$TB_LINEUP,$TB_PAGEDOWN,$TB_PAGEUP,$TB_THUMBTRACK
            WinSetTrans ($gui,"",GUICtrlRead($Slider_1))
    EndSwitch
EndFunc
ps.本来想多给几个例子的,不过再给文章长度就会超过限制...下周我还会继续讲解系统消息的其他应用。

hehui 发表于 2008-5-3 17:15:29

正在找ListView的双击响应,楼主真是太及时了!

viniko 发表于 2008-5-3 17:45:09

谢谢楼主的贴,,收藏起来,,慢慢学习

kangaroo 发表于 2008-5-6 15:45:07

谢谢楼主的知识。

流浪的风 发表于 2008-5-10 16:35:08

对于 我来说,嗯,还是高深了点。。。。。慢慢学习了。。。

ollydbg 发表于 2008-5-10 22:04:59

谢谢楼上的贴,收藏起来慢慢学习~!~!

bachelor66 发表于 2009-5-27 16:00:41

我要慢慢看了

fastpoint 发表于 2009-5-27 20:43:04

正好用得到!!!

andersonljw 发表于 2009-7-29 21:34:01

谢谢楼主,文章不错,正是需要

landays 发表于 2009-7-30 13:12:42

本帖最后由 landays 于 2009-7-30 13:15 编辑

慢慢看,谢谢

hongewuyan 发表于 2009-7-31 18:10:24

这个要收藏,要实现一些高级功能,这些是必不可少的知识

rasin 发表于 2009-8-5 19:22:09

好深的文章,,慢慢研究~~

cxckx 发表于 2009-8-8 18:40:18

不错,又学习了新东西。

ebook_zhh 发表于 2009-8-9 22:07:38

收藏了,非常感谢

suntalent 发表于 2009-8-10 17:21:34

路过水一下
页: [1] 2 3
查看完整版本: 转帖Autoit系统消息详解——GUI通知