jiarqq 发表于 2021-1-15 16:58:55

_GUICtrlTreeView_GetTree() 函数返回值为空

本帖最后由 jiarqq 于 2021-1-15 17:16 编辑

最近在做QQ文件自动接收的小工具。任务栏图标闪烁检测,【全另存为】按钮自动化点击都还顺利,可是在点击【全另存为】按钮之后选择保存位置时遇到了麻烦。



先说一下我的整体思路吧。

第一步:
检测QQ图标是否闪烁,如果闪烁则说明两种可能,一是【来文件了】,二是【来消息了】。不管是来消息还是来文件,一律自动化点击闪烁的托盘图标以弹出聊天窗口做进一步的判断。
第二步:
检查聊天窗口是否存在【全另存为】的按钮,如果存在则判定是 【来文件了】,然后寻找该按钮的相对于窗口的坐标,然后自动化点击。这两步骤不难实现。
第三步:(卡这了)
点击【全另存为】后,会立即弹出一个浏览文件夹对话框,让你选择接收文件的路径。

我用的是思路是这样的:

   A.先使用 _GUICtrlTreeView_FindItemEx(控件句柄,树目录路径) 函数,检索(树视图)指定树目录路径的项目。成功则返回:匹配树目录路径的第一个项目句柄。
   B.再使用 _GUICtrlTreeView_Expand(控件 ID 或句柄,项目句柄, True)展开项目

可是,我发现 AB两个步骤都出了问题,于是我试试注册表,发现一点问题都没有。真是奇怪。

以下是我的实验过程:
测试注册表时成功展开,见下图:




#RequireAdmin
#include <GuiTreeView.au3>

Opt("GUIDataSeparatorChar", "\");定义分隔符

;~ $hTreeView = ControlGetHandle('浏览文件夹', '', 'SysTreeView321');获取树控件句柄
$hTreeView = ControlGetHandle('注册表编辑器', '', 'SysTreeView321');获取树控件句柄
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hTreeView = ' & $hTreeView & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

;~ $hTreeView_Path = _GUICtrlTreeView_FindItemEx($hTreeView,'桌面\此电脑\');注意:不同系统【浏览文件夹】对话框显示的名称和路径有可能不一样,测试的时候记得改一下。
$hTreeView_Path = _GUICtrlTreeView_FindItemEx($hTreeView,'计算机\HKEY_CURRENT_USER\SOFTWARE\AutoIt v3');注意:不同系统【注册表】显示的名称或路径有可能不一样,测试的时候记得改一下。
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hTreeView_Path = ' & $hTreeView_Path & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
_GUICtrlTreeView_Expand($hTreeView,$hTreeView_Path,True);【浏览文件夹】指定路径展开失败,【注册表】指定路径展开成功,此函数没有返回值,只能看到状态:展开/折叠

测试QQ的浏览文件夹对话框,项目句柄及展开均失败。
#RequireAdmin
#include <GuiTreeView.au3>

Opt("GUIDataSeparatorChar", "\");定义分隔符

$hTreeView = ControlGetHandle('浏览文件夹', '', 'SysTreeView321');获取树控件句柄
;~ $hTreeView = ControlGetHandle('注册表编辑器', '', 'SysTreeView321');获取树控件句柄
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hTreeView = ' & $hTreeView & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

$hTreeView_Path = _GUICtrlTreeView_FindItemEx($hTreeView,'桌面\此电脑\');注意:不同系统【浏览文件夹】对话框显示的名称和路径有可能不一样,测试的时候记得改一下。
;~ $hTreeView_Path = _GUICtrlTreeView_FindItemEx($hTreeView,'计算机\HKEY_CURRENT_USER\SOFTWARE\AutoIt v3');注意:不同系统【注册表】显示的名称或路径有可能不一样,测试的时候记得改一下。
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hTreeView_Path = ' & $hTreeView_Path & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
_GUICtrlTreeView_Expand($hTreeView,$hTreeView_Path,True);【浏览文件夹】指定路径展开失败,【注册表】指定路径展开成功,此函数没有返回值,只能看到状态:展开/折叠



















ac5474012 发表于 2021-1-15 17:00:10

对QQ的gui判断会有问题,我更建议是屏幕像素检测。

zghwelcome 发表于 2021-1-15 21:24:12

试试这样#include <GuiTreeView.au3>

#RequireAdmin
#AutoIt3Wrapper_UseX64 = n
DllCall('User32.dll', 'BOOL', 'SetProcessDPIAware')
Local $hWnd_Control = ControlGetHandle('','','SysTreeView321')
Local $sExpandPath = '此电脑\Desktop\新建文件夹' , $sName
Local $aSplit = StringSplit($sExpandPath, '\', 2)
For $i = 0 To UBound($aSplit) - 1
        $sName = $aSplit[$i]
        _Expand($hWnd_Control ,$sName)
        If @error Then Exit MsgBox(0,0,'Err')
        If $i <> UBound($aSplit) -1 Then Sleep(800)
Next
ControlClick('','','')


Func _Expand($hWnd_Control, $sName)
        Local $hItem = _GUICtrlTreeView_FindItem($hWnd_Control,$sName)
        If Not $hItem Then Return SetError(1,0,'')
        _GUICtrlTreeView_Expand($hWnd_Control, $hItem, True)
        _GUICtrlTreeView_SetSelected($hWnd_Control,$hItem , True)
        _GUICtrlTreeView_ClickItem($hWnd_Control, $hItem)
EndFunc   ;==>_Expand

jiarqq 发表于 2021-1-16 18:56:01

zghwelcome 发表于 2021-1-15 21:24
试试这样

这样测试好像不行亲

afan 发表于 2021-1-16 19:26:00

控件句柄都没获取到,后面怎么可能继续…
建议贴上窗口探测信息以参考

jiarqq 发表于 2021-1-16 19:41:48

afan 发表于 2021-1-16 19:26
控件句柄都没获取到,后面怎么可能继续…
建议贴上窗口探测信息以参考

窗口句柄获取到了,

afan 发表于 2021-1-16 19:46:02

jiarqq 发表于 2021-1-16 19:41
窗口句柄获取到了,

控件
窗口何用?

jiarqq 发表于 2021-1-16 20:07:16

afan 发表于 2021-1-16 19:46
控件
窗口何用?
控件句柄已经获取到了

afan 发表于 2021-1-16 20:32:20

jiarqq 发表于 2021-1-16 20:07
控件句柄已经获取到了

不说了。




jiarqq 发表于 2021-1-17 02:03:04

afan 发表于 2021-1-16 20:32
不说了。

确实是函数的问题,这样改一下就可以了。

Func _GUICtrlTreeView_GetText32($hWnd, $hItem = 0)
If Not IsHWnd($hItem) Then $hItem = _GUICtrlTreeView_GetItemHandle($hWnd, $hItem)
If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)

If $hItem = 0x00000000 Then Return SetError(1, 1, "")

; All 8 byte data types for a 64 bit system changed to 4 byte uint's for a 32 bit system
Local $tagTVITEMEX32 = "struct; uint Mask;struct; uint hItem;uint State;uint StateMask;uint Text;int TextMax;int Image;int SelectedImage;int Children;uint Param; endstruct;" & _
"int Integral;uint uStateEx;uint hwnd;int iExpandedImage;int iReserved; endstruct"

Local $tTVITEM = DllStructCreate($tagTVITEMEX32)
Local $tText
Local $fUnicode = _GUICtrlTreeView_GetUnicodeFormat($hWnd)
If $fUnicode Then
    $tText = DllStructCreate("wchar Buffer"); create a text 'area' for receiving the text
Else
    $tText = DllStructCreate("char Buffer"); create a text 'area' for receiving the text
EndIf

DllStructSetData($tTVITEM, "Mask", $TVIF_TEXT)
DllStructSetData($tTVITEM, "hItem", BitShift( $hItem, -32 )) ; 8 byte value --> 4 byte value
DllStructSetData($tTVITEM, "TextMax", 4096)

If _WinAPI_InProcess($hWnd, $__ghTVLastWnd) Then
    DllStructSetData($tTVITEM, "Text", DllStructGetPtr($tText))
    _SendMessage($hWnd, $TVM_GETITEMW, 0, $tTVITEM, 0, "wparam", "struct*")
Else
    Local $iItem = DllStructGetSize($tTVITEM)
    Local $tMemMap
    Local $pMemory = _MemInit($hWnd, $iItem + 4096, $tMemMap)
    Local $pText = $pMemory + $iItem
    DllStructSetData($tTVITEM, "Text", BitShift( $pText, -32 )) ; 8 byte value --> 4 byte value
    _MemWrite($tMemMap, $tTVITEM, $pMemory, $iItem)
    If $fUnicode Then
      _SendMessage($hWnd, $TVM_GETITEMW, 0, BitShift( $pMemory, -32 ), 0, "wparam", "ptr") ; 8 byte value --> 4 byte value
    Else
      _SendMessage($hWnd, $TVM_GETITEMA, 0, $pMemory, 0, "wparam", "ptr")
    EndIf
    _MemRead($tMemMap, $pText, $tText, 4096)
    _MemFree($tMemMap)
EndIf

Return DllStructGetData($tText, "Buffer")
EndFunc

参考链接:https://www.autoitscript.com/forum/topic/173529-guictrltreeview-udf-64bit-script-on-x86-control/?tab=comments#comment-1255321


另附32位的UDF




大工告成:








jiarqq 发表于 2021-1-17 02:14:30

本帖最后由 jiarqq 于 2021-1-17 02:16 编辑

jiarqq 发表于 2021-1-17 02:03
确实是函数的问题,这样改一下就可以了。



试了下标准函数 ControlTreeView 也同样不能获取到项目句柄。

看了下备注:在 64 位 Windows 系统上运行 32 位的 AutoIt 时,部分命令可能无效, 此时请使用 64 位 AutoIt 版本.
另一处备注:使用 32 位 Autoit 进程读取 64 位进程时,命令可能会失败. 同理,反之也可能失败.

也许如此吧!




jiarqq 发表于 2021-1-17 02:17:04

本帖最后由 jiarqq 于 2021-1-17 16:00 编辑

jiarqq 发表于 2021-1-17 02:14
试了下标准函数 ControlTreeView 也同样不能获取到项目句柄。

看了下备注:在 64 位 Windows 系统上运 ...
QQ是32位进程,而我使用的是AutoIt3_x64运行的脚本。
页: [1]
查看完整版本: _GUICtrlTreeView_GetTree() 函数返回值为空