xiehuahere 发表于 2010-4-7 19:11:01

如何获取ToolbarWindow32控件上某个按钮的状态

本帖最后由 xiehuahere 于 2010-4-7 19:12 编辑

AutoIt新手。看了CHM帮助,没有找到唉。论坛里也没有搜索到......求赐教

这个ToolbarWindow32控件不是我用脚本create的,而是某个已知软件上的。
我如何得知该控件上的某个按钮是不是 Enabled 状态?
有没有类似WinWaitActive之类的函数等待此按钮的激活状态呢?(QTP自动测试工具提供此方法)
谢谢了~

lainline 发表于 2010-4-7 20:54:57

这个会不会太难 AccExplorer32

本帖最后由 lainline 于 2010-4-8 10:57 编辑

控件本身
$htemp =ControlGetHandle("","","[CLASSNN:ToolbarWindow322")
$text =WinGetText($htemp,"")
ToolTip($htemp)
MsgBox(0,$text,"存在:"& BitAND(WinGetState($htemp,""),1))
MsgBox(0,$text,"可用:"& BitAND(WinGetState($htemp,""),4))
MsgBox(0,$text,"可见:"& BitAND(WinGetState($htemp,""),2))
MsgBox(0,$text,"激活:"& BitAND(WinGetState($htemp,""),8))
MsgBox(0,$text,"最小化:"& BitAND(WinGetState($htemp,""),16))
MsgBox(0,$text,"最大化:"& BitAND(WinGetState($htemp,""),32))

下面具体到按钮就有些难了

工具:

示例代码从英文站上找来的如果要看原文可以到英文站上搜索
#include <WinAPI.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <StaticConstants.au3>
#include <Array.au3>

;~ opt("MustDeclareVars", 1)
Opt("GUIOnEventMode", 1)

Global $oMyError = ObjEvent("AutoIt.Error", "MyErrFunc")

Global Const $hOLE32 = DllOpen("ole32.dll")
Global Const $hOLEACC = DllOpen("oleacc.dll")
Global Const $hOleAut = DllOpen("oleaut.dll")

Global Const $VT_EMPTY = 0
Global Const $VT_NULL = 1
Global Const $VT_I2 = 2
Global Const $VT_I4 = 3
Global Const $VT_R4 = 4
Global Const $VT_R8 = 5
Global Const $VT_CY = 6
Global Const $VT_DATE = 7
Global Const $VT_BSTR = 8
Global Const $VT_DISPATCH = 9
Global Const $VT_ERROR = 10
Global Const $VT_BOOL = 11
Global Const $VT_VARIANT = 12
Global Const $VT_UNKNOWN = 13
Global Const $VT_DECIMAL = 14
Global Const $VT_I1 = 16
Global Const $VT_UI1 = 17
Global Const $VT_UI2 = 18
Global Const $VT_UI4 = 19
Global Const $VT_I8 = 20
Global Const $VT_UI8 = 21
Global Const $VT_INT = 22
Global Const $VT_UINT = 23
Global Const $VT_VOID = 24
Global Const $VT_HRESULT = 25
Global Const $VT_PTR = 26
Global Const $VT_SAFEARRAY = 27
Global Const $VT_CARRAY = 28
Global Const $VT_USERDEFINED = 29
Global Const $VT_LPSTR = 30
Global Const $VT_LPWSTR = 31
Global Const $VT_RECORD = 36
Global Const $VT_INT_PTR = 37
Global Const $VT_UINT_PTR = 38
Global Const $VT_FILETIME = 64
Global Const $VT_BLOB = 65
Global Const $VT_STREAM = 66
Global Const $VT_STORAGE = 67
Global Const $VT_STREAMED_OBJECT = 68
Global Const $VT_STORED_OBJECT = 69
Global Const $VT_BLOB_OBJECT = 70
Global Const $VT_CF = 71
Global Const $VT_CLSID = 72
Global Const $VT_VERSIONED_STREAM = 73
Global Const $VT_BSTR_BLOB = 0xfff
Global Const $VT_VECTOR = 0x1000
Global Const $VT_ARRAY = 0x2000
Global Const $VT_BYREF = 0x4000
Global Const $VT_RESERVED = 0x8000
Global Const $VT_ILLEGAL = 0xffff
Global Const $VT_ILLEGALMASKED = 0xfff
Global Const $VT_TYPEMASK = 0xfff

;~ Global Const $tagGUID = "ulong;ushort;ushort;byte"
Global Const $tagCLSID = $tagGUID
Global Const $tagUUID = $tagGUID
Global Const $CLSCTX_INPROC_SERVER = 0x1
Global Const $S_OK = 0
Global Const $DISP_E_UNKNOWNNAME = 2147614726
Global Const $DISPID_UNKNOWN = 4294967295
Global Const $DISP_E_MEMBERNOTFOUND = 2147614723
Global Const $tagVARIANT = "ushort vt;ushort r1;ushort r2;ushort r3;uint64 data"
Global Const $tagDISPPARAMS = "ptr rgvargs;ptr rgdispidNamedArgs;dword cArgs;dword cNamedArgs;"

Global Const $DISPATCH_METHOD = 0x1
Global Const $DISPATCH_PROPERTYGET = 0x2
Global Const $DISPATCH_PROPERTYPUT = 0x4
Global Const $DISPATCH_PROPERTYPUTREF = 0x8

Global Const $tagLOOKUP_TABLE_ENTRY = "ptr name;ptr value;dword flags;"
Global Const $LOOKUP_TABLE_ENTRY_SIZE = DllStructGetSize(DllStructCreate($tagLOOKUP_TABLE_ENTRY))
Global Const $LOOKUP_TABLE_METHOD = 1
Global Const $LOOKUP_TABLE_PROPERTY = 2
Global Const $LOOKUP_TABLE_PUBLIC = 0
Global Const $LOOKUP_TABLE_PRIVATE = 4

Global Const $tagOBJECT_INFO = "dword refcount;ptr release;"

Global Const $hOLEOUT = DllOpen("oleaut32.dll")

Global Const $SizeOfPtr = DllStructGetSize(DllStructCreate("ptr"))
Global $myEdit

GUICreate("MSAA Spy")
$myEdit = GUICtrlCreateEdit("First line" & @CRLF, 10, 10, 400, 300, $ES_AUTOVSCROLL + $WS_VSCROLL)
GUISetOnEvent(-3, "_Quit")
GUISetState()

Global $aMousePos, $aCall, $oIAccesible
Global $tInfo
global $oChild

Global Const $__Au3Obj_tagVARIANT = "ushort vt;ushort r1;ushort r2;ushort r3;ptr data; ptr"
Global $tVar = DllStructCreate($__Au3Obj_tagVARIANT)
Global $pVar = DllStructGetPtr($tVar)
__Au3Obj_VariantInit($pVar)

While 1

    $aMousePos = MouseGetPos()
    $aCall = DllCall($hOLEACC, "int", "AccessibleObjectFromPoint", _
            "int", $aMousePos, _
            "int", $aMousePos, _
            "ptr*", 0, _
            "ptr", $pVar)
;~             "ptr", $pVar)

    If @error Or $aCall<>0 Then
      ConsoleWrite("!DLLCall-Error or error on receiving IAccesible" & @CRLF)
      Sleep(500)
      ContinueLoop
    EndIf
    $oIAccesible = __Au3Obj_ConvertPtrToIDispatch($aCall) ; create IDispatch when no error occured

    If IsObj($oIAccesible) Then
    ; ConsoleWrite("accChild: " & $oAccessibleObject.accChild($Param) & @CRLF) ;<-

    GUICtrlSetData($myedit, "")
;~$oChild=$oIAccesible.accchild
   
    $x=int(2+$oChild)-2
    dim $array =
    if COMVariantToValue($pVar)<15 then
      $oChild=$array
    Else
      $oChild=0
    endif
    $tInfo=$x & @CRLF
    $tInfo = $tinfo & "accChildCount: " & $oIAccesible.accChildCount($oChild)& @CRLF
    $tInfo = $tinfo & "accDefaultAction: " & $oIAccesible.accDefaultAction($oChild) & @CRLF
    $tInfo = $tinfo & "accDescription: " & $oIAccesible.accDescription($oChild) & @CRLF
    $tInfo = $tinfo & "accFocus: " & $oIAccesible.accFocus($oChild) & @CRLF
    $tInfo = $tinfo & "accHelp: " & $oIAccesible.accHelp($oChild) & @CRLF
;~   $tInfo = $tinfo & "accHelpTopic: " & $oIAccesible.accHelpTopic($Param) & @CRLF
    $tInfo = $tinfo & "accKeyboardShortcut: " & $oIAccesible.accKeyboardShortcut & @CRLF
    $tInfo = $tinfo & "accName: " & $oIAccesible.accName($oChild) & @CRLF
;~$tInfo = $tinfo & "accName: " & $oIAccesible.accName(number($oChild)) & @CRLF
;~$tInfo = $tinfo & "accName: " & $oIAccesible.accName(int($oChild)) & @CRLF
      
    $tInfo = $tinfo & "accParent: " & $oIAccesible.accParent($oChild) & @CRLF
    dim $sText
   
    ;- Get the textual description of the role
    local $aRoleCall = DllCall($hOLEACC, "int", "GetRoleText", "DWORD", $oIAccesible.accRole($oChild), "str", $sText, "int", 255)
   
    $tInfo = $tinfo & "accRole: " & $oIAccesible.accRole($oChild) & ":" & $aRoleCall & @CRLF
    $tInfo = $tinfo & "accSelection: " & $oIAccesible.accSelection($oChild) & @CRLF
    $tInfo = $tinfo & "accState: " & $oIAccesible.accState($oChild) & @CRLF
    $tInfo = $tinfo & "accValue: " & $oIAccesible.accValue($oChild) & @CRLF
   
    dim $pX,$pY,$cX,$cY
;~$oIAccesible.accLocation($px,$py,$cx,$cy,$oChild)
    $oIAccesible.accLocation($px,$py,$cx,$cy,$pVar)
   
    $tInfo = $tinfo & "accLocation: " & $px & $py & $cx & $cy & @CRLF
    GUICtrlSetData($myedit, $tInfo)
   
    Else
      ConsoleWrite("! NOT OBJECT" & @CRLF)
    EndIf

;~ Do not forget to clean the return result
    __Au3Obj_VariantClear($aCall)
    $oIAccesible = 0 ; free Object
    Sleep(500)

WEnd

Func MyErrFunc()
    ConsoleWrite("!COM Error!   " & "Number is: " & Hex($oMyError.number, 8) & "description is: " & $oMyError.windescription & @CRLF)
EndFunc   ;==>MyErrFunc

; FUNCTIONS:

Func _GetObjectWinHandle($oObject)

    Local $aCall = DllCall("oleacc.dll", "int", "WindowFromAccessibleObject", _
            "idispatch", $oObject, _
            "hwnd*", 0)

    If @error Or $aCall Then
      Return SetError(1, 0, 0)
    EndIf

    Return $aCall

EndFunc   ;==>_GetObjectWinHandle

Func _AccessibleObjectFromWindow($hWnd)

    Local $sIID_IAccessible = "{618736E0-3C3D-11CF-810C-00AA00389B71}"
    Local $tGUID = _WinAPI_GUIDFromString($sIID_IAccessible)
    Local $pGUID = DllStructGetPtr($tGUID)

    Local $aCall = DllCall($hOLEACC, "int", "AccessibleObjectFromWindow", _
            "hwnd", $hWnd, _
            "dword", 0, _ ; OBJID_WINDOW
            "ptr", $pGUID, _
            "idispatch*", 0)

    If @error Or $aCall Then
      Return SetError(1, 0, 0)
    EndIf

    Return $aCall

EndFunc   ;==>_AccessibleObjectFromWindow
Func _AccessibleObjectFromPoint($x,$y)
    Local $tPoint=DllStructCreate($tagPOINT)
    dllstructsetdata($tPoint,1,$x)
    dllstructsetdata($tPoint,2,$y)
;~ STDAPI AccessibleObjectFromWindow(__in   HWND hwnd,__in   DWORD dwObjectID,__in   REFIID riid,__outvoid **ppvObject);
;~ STDAPI AccessibleObjectFromPoint(__in   POINT ptScreen,__outIAccessible **ppacc,__outVARIANT *pvarChild);
;~   local $aCall = DllCall($hOLEACC, "int", "AccessibleObjectFromPoint", "ptr", DllStructGetPtr($tPOINT), "idispatch*", 0, "ptr", 0)
;~   local $aCall = DllCall($hOLEACC, "int", "AccessibleObjectFromPoint", "long", DllStructGetPtr($tPOINT), "idispatch", 0, "ptr", 0)
    local $aCall = DllCall($hOLEACC, "int", "AccessibleObjectFromPoint", "int", $x, "int", $y, "idispatch*", 0, "ptr", 0)
    If @error Or $aCall Then
      Return SetError(1, 0, 0)
    EndIf

    Return ConvertPtrToIDispatch($aCall)

EndFunc   ;==>_AccessibleObjectFromWindow
; In the end we still want the autoit object. This function converts a raw pointer to an autoit object
Func ConvertPtrToIDispatch($pIDispatch)
    ; This would have been 10000x easier if autoit had supported the idispatch* type in dllstructs...
    ; Fortunetely memcpy can copy the pointer into a idispatch*, lucky us.
    Local $aCall = DllCall("kernel32.dll", "none", "RtlMoveMemory", _
            "idispatch*", 0, _
            "ptr*", $pIDispatch, _
            "dword", 4)

    If @error Then
      Return SetError(1, 0, 0)
    EndIf

    Return $aCall

EndFunc ;==>ConvertPtrToIDispatch

Func __Au3Obj_ConvertPtrToIDispatch($pIDispatch)
    ; Author: monoceres
    Local $iSize = 4+(4*@AutoItX64)
    Local $aCall = DllCall("kernel32.dll", "none", "RtlMoveMemory", "idispatch*", 0, "ptr*", $pIDispatch, "dword", $iSize)
    If @error Then Return SetError(1, 0, 0)
    Return $aCall
EndFunc   ;==>__Au3Obj_ConvertPtrToIDispatch
Func __Au3Obj_VariantClear($pvarg)
    ; Author: Prog@ndy
    Local $aCall = DllCall($hOleAut, "long", "VariantClear", "ptr", $pvarg)
    If @error Then Return SetError(1, 0, 1)
    Return $aCall
EndFunc   ;==>__Au3Obj_VariantClear
Func __Au3Obj_VariantInit($pvarg)
    ; Author: Prog@ndy
    Local $aCall = DllCall($hOleAut, "long", "VariantInit", "ptr", $pvarg)
    If @error Then Return SetError(1, 0, 1)
    Return $aCall
EndFunc   ;==>__Au3Obj_VariantInit

Func VTType2AutoitType($iVT_Type)
    ConsoleWrite("! " & $iVT_Type & @CRLF)
    Switch $iVT_Type
      Case $VT_I1
            Return "byte"
      Case $VT_I2
            Return "short"
      Case $VT_I4
            Return "int"
      Case $VT_BSTR
            Return "wstr"
      Case $VT_R8
            Return "double"
      Case $VT_DISPATCH
            Return "idispatch"
    EndSwitch
EndFunc ;==>VTType2AutoitType
Func COMVariantToValue($pVariant)
    Local $hVariant = DllStructCreate($tagVARIANT, $pVariant)
    ; Translate the vt id to a autoit dllcall type
    $sType = VTType2AutoitType(DllStructGetData($hVariant, "vt"))


    If $sType = "wstr" Then
      $pString = DllStructCreate("ptr", DllStructGetPtr($hVariant, "data"))
      ; Getting random crashes when trusting autoit to automatically use right size.
      ; doing it myself instead (also, it should be a BSTR, but it's not. Is autoit not obeying the rules!?
      $iString_Size = wcslen(DllStructGetData($pString, 1))

      ; Sorry trancexx, doesn't seem to work on large strings (crashes like crazy when trying to use on 1 MB string)
      ;$tSub = DllStructCreate("dword", DllStructGetData($str_ptr, 1) - 4) ; <- move pointer back 4 bytes!

      $hData = DllStructCreate("wchar[" & $iString_Size & "]", DllStructGetData($pString, 1))

    ElseIf $sType = "idispatch" Then

      Return ConvertPtrToIDispatch(DllStructGetData(DllStructCreate("ptr", DllStructGetPtr($hVariant, "data")), 1))

    Else
      $hData = DllStructCreate($sType, DllStructGetPtr($hVariant, "data"))
    EndIf

    Return DllStructGetData($hData, 1)
EndFunc ;==>COMVariantToValue

; Find out length of string. I do not trust autoit to do this.
Func wcslen($pWString)
    $aCall = DllCall("ntdll.dll", "dword:cdecl", "wcslen", "ptr", $pWString)
    Return $aCall
EndFunc ;==>wcslen



Func _Quit()

    Exit

EndFunc   ;==>_Quit
;

xiehuahere 发表于 2010-4-8 09:40:42

楼上的辛苦了。
就控件本身的那段代码,我看明白了。
具体到按钮,确实那个。。。非常复杂。QTP下面一个语句就完成的事情,到AutoIt中真是不可想象。把我给吓住了啊。没有简单一些的方法了吗?
谢谢帮忙,我再下去研究一下啊。

kwyking 发表于 2010-4-8 15:39:11

thank you very much

pusofalse 发表于 2010-4-8 22:33:57

看了CHM帮助,没找到? - -|||
#include <GUIToolbar.au3>
_GUICtrlToolbar_GetButtonState($hWnd, $iCommandID)

xiehuahere 发表于 2010-4-9 09:52:22

版主,你好!

这个函数我是看到了的,但我认为这是用在Toolbar是自己创建的前提下,才能得知它的句柄。
否则,每次软件打开的时候,句柄都不一样,第一个参数如何填写呢?
困惑。。。请指教啊

lainline 发表于 2010-4-9 10:42:06

本帖最后由 lainline 于 2010-4-9 10:43 编辑

控件类型和序号不会变的 用ControlGetHandle获取句柄
另外我正在搜集oleacc.dll的调用函数 准备做个库

还是觉得这个技术比较有用详见
http://www.vckbase.com/document/viewdoc/?id=883

xiehuahere 发表于 2010-4-9 12:50:42

本帖最后由 xiehuahere 于 2010-4-9 13:29 编辑

谢谢,可为什么我获取出来的状态值始终是-1呢?#include <GUIToolbar.au3>

WinActivate("TestWindow")
WinWaitActive("TestWindow")
ControlFocus("TestWindow", "", "ToolbarWindow321")

$hToolbar = ControlGetHandle("TestWindow", "", "ToolbarWindow321") ;TestWindow是我的窗口标题
$buttonStatus = _GUICtrlToolbar_GetButtonState($hToolbar, 3) ;Toolbar上的第3个按钮
MsgBox(0, "Button", $buttonStatus)_GUICtrlToolbar_GetButtonState($hWnd, $iCommandID)
不知道其中的 $iCommandID 是什么意思,从哪里来的。汗......

lainline 发表于 2010-4-9 13:51:50

本帖最后由 lainline 于 2010-4-9 14:30 编辑

ControlGetHandle("TestWindow","","")



GUICtrlToolbar 好像不行大概是程序独立内存问题

xiehuahere 发表于 2010-4-9 14:55:54

貌似不需要 吧
帮助里的例子也没有这样用啊:$handle = ControlGetHandle("Untitled - Notepad", "", "Edit1")

我的$iCommandID也是从1开始的,我是Toolbar上的第3个按钮,可还是返回-1啊

已经Enable的效果:


鼠标放到按钮上的效果:

lainline 发表于 2010-4-9 16:51:01

按钮经过OLE封装对外属性是私有的只能经过DLL调用

xiehuahere 发表于 2010-4-9 17:28:03

好,知道了。谢谢。
页: [1]
查看完整版本: 如何获取ToolbarWindow32控件上某个按钮的状态