找回密码
 加入
搜索
查看: 2901|回复: 18

[AU3基础] 【已解决】关于GUIRegisterMsg注册0x0219何时能接收到消息

[复制链接]
发表于 2022-4-8 22:54:02 | 显示全部楼层 |阅读模式
本帖最后由 smooth 于 2022-4-18 10:15 编辑

通过查Windows消息代码得知,0x0219表示"当设备的硬件配置改变时,发送本消息给应用程序或设备驱动程序",但是注册0x0219后,什么情况下可以接收到Windows的消息呢?
下面的日志,第一部分(第一列*号后面)为设备未插入电脑时的日志,第二和第三部分为设备插入电脑的日志。
有两个疑问:
1、为什么设备插入电脑,绝大多数情况下,会发出两次Windows消息?即下面第二部分和第三部分日志。可以看到第二部分日志中,只执行了函数_Det_HardID,还未来得及执行_Get_Key,就又收到了Windows消息,然后就到了第三部分日志。
2、偶然的情况下,只收到一次Windows消息,而且是只执行完函数_Det_HardID,就停住了,没有继续执行_Get_Key函数,不懂什么原因,不知道有没有大佬对这个有研究的。


正常情况下的日志:
2022-04-08 22:22:28 : 正在启动软件......
2022-04-08 22:22:28 : *****************************************************************(第一部分)
2022-04-08 22:22:28 : 软件启动,开始检测U-KEY信息......
2022-04-08 22:22:28 : 函数_Det_HardID读取设备实例路径(ID)失败!
2022-04-08 22:22:29 : 函数_Get_Key读取U-KEY证书信息成功!
2022-04-08 22:22:29 : 运行官方证书管理工具成功,进程标识符: 8888
2022-04-08 22:22:30 : 函数 _Get_Key读取U-KEY证书信息失败,开始更新控件数据!
2022-04-08 22:22:38 : *****************************************************************(第二部分)
2022-04-08 22:22:38 : 设备的硬件配置发生改变,开始检测U-KEY信息......
2022-04-08 22:22:38 : 函数_Det_HardID读取设备实例路径(ID)成功!
2022-04-08 22:22:41 : *****************************************************************(第三部分)
2022-04-08 22:22:41 : 设备的硬件配置发生改变,开始检测U-KEY信息......
2022-04-08 22:22:41 : 函数_Det_HardID读取设备实例路径(ID)成功!
2022-04-08 22:22:41 : 函数_Get_Key读取U-KEY证书信息成功,开始更新控件数据!
2022-04-08 22:22:41 : 数据写入列表视图成功!


异常情况下的日志:
2022-04-08 22:22:28 : 正在启动软件......
2022-04-08 22:22:28 : *****************************************************************(第一部分)
2022-04-08 22:22:28 : 软件启动,开始检测U-KEY信息......
2022-04-08 22:22:28 : 函数_Det_HardID读取设备实例路径(ID)失败!
2022-04-08 22:22:29 : 函数_Get_Key读取U-KEY证书信息成功!
2022-04-08 22:22:29 : 运行官方证书管理工具成功,进程标识符: 8888
2022-04-08 22:22:30 : 函数 _Get_Key读取U-KEY证书信息失败,开始更新控件数据!
2022-04-08 22:22:38 : *****************************************************************(第二部分)
2022-04-08 22:22:38 : 设备的硬件配置发生改变,开始检测U-KEY信息......
2022-04-08 22:22:38 : 函数_Det_HardID读取设备实例路径(ID)成功!
                                 这里应该继续执行函数 _Get_Key,可是没有执行。
Func _U_KEY_Monitor($hWnd, $uMsg, $wParam, $lParam) ;监控U-KEY的插入和拔出
 Global $jn = 0 ;日志
 If $iDet_HardID_CS = 0 Then
  _FileWriteLog($hLogFile, _StringRepeat("*", 100))
     _FileWriteLog($hLogFile, "软件启动,开始检测U-KEY信息......")
     $iDet_HardID_CS = 1
    Else
     _FileWriteLog($hLogFile, _StringRepeat("*", 100))
     _FileWriteLog($hLogFile, "设备的硬件配置发生改变,开始检测U-KEY信息......")
 EndIf
 If StringLen(_Det_HardID()) > 6 Then
  _FileWriteLog($hLogFile, "函数_Det_HardID读取设备实例路径(ID)成功!")
  If StringLen(_Get_Key()) > 6 Then ;如果能检测到设备实例ID,再进一步检测证书,如果二者都能检测到,则更新控件。
   _FileWriteLog($hLogFile, "函数_Get_Key读取U-KEY证书信息成功,开始更新控件数据!")
   If _GUICtrlListView_GetItemCount($idListview) = 0 Then
       _Key_GuiSetData()
   EndIf
  ElseIf StringLen(_Get_Key()) < 6 Then ;能检测到设备实例ID(当然也有可能检测到的是制单和审核U盾的设备实例ID),但无法检测到证书。
   _FileWriteLog($hLogFile, "函数_Get_Key读取U-KEY证书信息失败!")
   If Not ProcessExists(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具"))) Then
    Local $iRunDBTool = Run($DBTool_SPDB, "", @SW_MINIMIZE)
    If @error Then
     _FileWriteLog($hLogFile, "运行官方证书管理工具失败,失败类型: " & @error)
    Else
     _FileWriteLog($hLogFile, "运行官方证书管理工具成功,进程标识符: " & $iRunDBTool)
    EndIf
   EndIf
   WinWait("浦发银行U-KEY管理工具", "", 10)
   Do ;这里如果不做循环等待,可能会出现不能关闭窗口进程的情况。
    If WinExists("浦发银行U-KEY管理工具") Then
     ProcessClose(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具")))
    EndIf
   Until Not ProcessExists(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具")))
   _Get_Key() ;运行证书管理工具之后,如果此时系统没有硬件发生变动, _Get_Key()不会在执行了,所以还是读取不到证书的信息,所以这里必须再运行一次 _Get_Key()函数。
   _FileWriteLog($hLogFile, "函数 _Get_Key读取U-KEY证书信息成功,开始更新控件数据!")
   If _GUICtrlListView_GetItemCount($idListview) = 0 Then
       _Key_GuiSetData()
   EndIf
  EndIf
 ElseIf StringLen(_Det_HardID()) < 6 Then
  _FileWriteLog($hLogFile, "函数_Det_HardID读取设备实例路径(ID)失败!")
  If StringLen(_Get_Key()) < 6 Then ;如果检测不到设备实例ID,也检测不到证书,说明U盾已拔除,并且系统中没有残留证书信息,直接更新控件。
   _FileWriteLog($hLogFile, "函数_Get_Key读取U-KEY证书信息失败!开始更新控件数据!")
   _NoKey_GuiSetData()
  ElseIf StringLen(_Get_Key()) > 6 Then ;如果不能检测到设备实例ID,但是能检测到证书,说明证书信息残留在系统中。
   _FileWriteLog($hLogFile, "函数_Get_Key读取U-KEY证书信息成功!")
   If Not ProcessExists(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具"))) Then
    Local $iRunDBTool = Run($DBTool_SPDB, "", @SW_MINIMIZE)
    If @error Then
     _FileWriteLog($hLogFile, "运行官方证书管理工具失败,失败类型: " & @error)
    Else
     _FileWriteLog($hLogFile, "运行官方证书管理工具成功,进程标识符: " & $iRunDBTool)
    EndIf
   EndIf
   WinWait("浦发银行U-KEY管理工具", "", 10)
   Do ;这里如果不做循环等待,可能会出现不能关闭窗口进程的情况。
    If WinExists("浦发银行U-KEY管理工具") Then
     ProcessClose(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具")))
    EndIf
   Until Not ProcessExists(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具")))
   _Get_Key() ;运行证书管理工具之后,如果此时系统没有硬件发生变动, _Get_Key()不会在执行了,所以还是能读取到残留的证书信息,所以这里必须再运行一次 _Get_Key()函数。
   _FileWriteLog($hLogFile, "函数 _Get_Key读取U-KEY证书信息失败,开始更新控件数据!")
   _NoKey_GuiSetData()
  EndIf
 EndIf
 Return True ;不处理来自AutoIt内部的消息,换言之,就是只处理来自Windows的消息。
EndFunc   ;==>_U_KEY_Monitor











发表于 2022-4-9 10:55:29 | 显示全部楼层
虽然没代码纯靠猜,但也几乎可以断定是处理消息没有即时返回,这类问题已提醒过N次。
 楼主| 发表于 2022-4-9 11:30:26 | 显示全部楼层
本帖最后由 smooth 于 2022-4-9 12:04 编辑
afan 发表于 2022-4-9 10:55
虽然没代码纯靠猜,但也几乎可以断定是处理消息没有即时返回,这类问题已提醒过N次。

不好意思,我对注册消息函数不熟悉,最近一直在百度里搜相关资料学习,云里雾里的。我以为是消息机制的问题,所以没发代码上来,且消息函数里调用了第三方的exe,代码发了怕大家说代码不可运行。

不明白返回是什么意思,也不明白为什么要返回。是不是在每一次判断执行好了之后,就加个return 0?
发表于 2022-4-9 13:00:30 | 显示全部楼层
smooth 发表于 2022-4-9 11:30
不好意思,我对注册消息函数不熟悉,最近一直在百度里搜相关资料学习,云里雾里的。我以为是消息机制的问 ...

Windows 消息在传递到程序后需要尽快处理后返回到系统,以让系统继续处理或停止处理该消息。否则会等待造成诸如消息中断、系统挂起、僵滞等问题。
消息函数中只适合处理毫秒级、轻量级的任务。耗时的任务应使用在函数外执行的手段,比如做变量标识、定时执行等。
 楼主| 发表于 2022-4-9 13:42:32 | 显示全部楼层
afan 发表于 2022-4-9 13:00
Windows 消息在传递到程序后需要尽快处理后返回到系统,以让系统继续处理或停止处理该消息。否则会等待造 ...

谢谢A大,看了你的解释,已大概明白其中的道理,但是不知道怎么实现。到底是return 0,还是return 1。
我看了帮助的例子,两个都用了,return 0的注释: Only workout clicking on the button(仅仅在点击按钮时锻炼?),Return 1 的注释:The internal AutoIt message handler will not run(Autoit内部消息句柄不会运行)。不怎么明白分别有什么作用。
发表于 2022-4-9 13:56:36 | 显示全部楼层
smooth 发表于 2022-4-9 13:42
谢谢A大,看了你的解释,已大概明白其中的道理,但是不知道怎么实现。到底是return 0,还是return 1。
...

你的问题是消息函数内的任务过重,随意看那几个 WinWait 就够崩溃的了。解决方法如上所述。
这里的返回是指返回系统,不需要 Return 值,函数执行完就是返回了。你的问题是函数执行完整个过程太耗时。
再不理解就不解释了。
 楼主| 发表于 2022-4-9 14:18:44 | 显示全部楼层
afan 发表于 2022-4-9 13:56
你的问题是消息函数内的任务过重,随意看那几个 WinWait 就够崩溃的了。解决方法如上所述。
这里的返回 ...

我理解。就是只要消息一出现,就马上处理,处理完毕就返回系统。

只是不明白,大概需要多快才不影响,另外不知道怎么实现你说的轻量化,得好好研究。
发表于 2022-4-10 00:58:58 | 显示全部楼层
两个人不在一个频道上,楼主根本都没理解a版的讲解。
通俗点讲,不是多快的问题,就是让你把主循环里面的WinWait,Sleep等等去掉。
 楼主| 发表于 2022-4-10 09:33:41 | 显示全部楼层
haijie1223 发表于 2022-4-10 00:58
两个人不在一个频道上,楼主根本都没理解a版的讲解。
通俗点讲,不是多快的问题,就是让你把主循环里面的W ...

因为是控制鼠标操作,没有winwait、sleep,脚本就实现不了既定功能。
发表于 2022-4-10 09:45:10 | 显示全部楼层
smooth 发表于 2022-4-10 09:33
因为是控制鼠标操作,没有winwait、sleep,脚本就实现不了既定功能。

哎~要不你花点钱,请人帮你写。会节约好多时间,顺便学习一下别人的思路。毕竟时间的本质也是金钱。
 楼主| 发表于 2022-4-10 10:56:35 | 显示全部楼层
本帖最后由 smooth 于 2022-4-10 10:57 编辑
haijie1223 发表于 2022-4-10 09:45
哎~要不你花点钱,请人帮你写。会节约好多时间,顺便学习一下别人的思路。毕竟时间的本质也是金钱。

我已经搞好了,我对细节要求太高了,所以经常在改。等下次吧。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
发表于 2022-4-10 11:12:48 | 显示全部楼层
smooth 发表于 2022-4-10 10:56
我已经搞好了,我对细节要求太高了,所以经常在改。等下次吧。

你那些所谓的要求高,在别人那里都是常规操作。
搞好就好,给你点赞!大佬牛逼!
 楼主| 发表于 2022-4-10 23:18:32 | 显示全部楼层
本帖最后由 smooth 于 2022-4-10 23:27 编辑
afan 发表于 2022-4-9 13:56
你的问题是消息函数内的任务过重,随意看那几个 WinWait 就够崩溃的了。解决方法如上所述。
这里的返回 ...

A大,我按照你说的,消息函数里只用来管一个变量,以减轻它的任务负担,然后把里面的工作任务移出去,放入一个新的函数里(假设为_UKEY_Monitor),根据变量来判断何时执行,但是结果还是一样。有时候_UKEY_Monitor函数执行到一半,就跳转到While循环里面去了,_UKEY_Monitor函数就执行不完整。摘出来的部分代码如下:

Global $U_KEY_Monitor = False

GUIRegisterMsg(0x0219, '_WM_DEVICECHANGE')
Func _WM_DEVICECHANGE($hWnd, $uMsg, $wParam, $lParam) ;接收设备的硬件配置发生改变时发出的Windows消息。
      $U_KEY_Monitor = True
      Return True
EndFunc   ;==>_U_KEY_Monitor



While 1 ;主循环
       Sleep(1)
       If $U_KEY_Monitor = True Then
           _UKEY_Monitor()
           $U_KEY_Monitor = False
      EndIf
Wend


我现在的补救方法是做一个定时器,一旦检测到A函数没执行完,然后就再执行一遍A函数。但是我不晓得是不是还有更好的解决办法。







发表于 2022-4-11 09:42:23 | 显示全部楼层
Global $U_KEY_Monitor = False

GUIRegisterMsg(0x0219, '_WM_DEVICECHANGE')

Func _WM_DEVICECHANGE($hWnd, $uMsg, $wParam, $lParam) ;接收设备的硬件配置发生改变时发出的Windows消息。
        $U_KEY_Monitor = True
;~         Return True
        Return $GUI_RUNDEFMSG

EndFunc   ;==>_WM_DEVICECHANGE

While 1 ;主循环
        Sleep(200)
        If $U_KEY_Monitor = True Then
                _UKEY_Monitor()
                $U_KEY_Monitor = False
        EndIf
WEnd
1,至少修改以上两处。
2,自查_UKEY_Monitor()什么情况下中断而不执行完,这应该是毫无难度的事。
 楼主| 发表于 2022-4-11 10:33:37 | 显示全部楼层
本帖最后由 smooth 于 2022-4-11 11:07 编辑
afan 发表于 2022-4-11 09:42
Global $U_KEY_Monitor = False

GUIRegisterMsg(0x0219, '_WM_DEVICECHANGE')

已按照你的建议进行了修改,问题还是一样。我再看看。

Func _UKEY_Monitor() ;监控U-KEY的插入和拔出
 $jn = 0 ;日志
 If $iDet_HardID_CS = 0 Then
  _FileWriteLog($hLogFile, _StringRepeat("*", 100))
     _FileWriteLog($hLogFile, "软件启动,开始检测U-KEY信息......")
     $iDet_HardID_CS = 1
    Else
     _FileWriteLog($hLogFile, _StringRepeat("*", 100))
     _FileWriteLog($hLogFile, "设备的硬件配置发生改变,开始检测U-KEY信息......")
 EndIf
 If StringLen(_Det_HardID()) > 6 Then
  _FileWriteLog($hLogFile, "函数_Det_HardID读取设备实例路径(ID)成功!")
  If StringLen(_Get_Key()) > 6 Then ;如果能检测到设备实例ID,再进一步检测证书,如果二者都能检测到,则更新控件。
   _FileWriteLog($hLogFile, "函数_Get_Key读取U-KEY证书信息成功!")
   _FileWriteLog($hLogFile, "开始更新控件数据!")
   If _GUICtrlListView_GetItemCount($idListview) = 0 Then
       _Key_GuiSetData()
    If _GUICtrlListView_GetItemCount($idListview) > 0 Then
        _FileWriteLog($hLogFile, "更新控件数据成功!")
       EndIf 
   EndIf
  ElseIf StringLen(_Get_Key()) < 6 Then ;能检测到设备实例ID(当然也有可能检测到的是制单和审核U盾的设备实例ID),但无法检测到证书,就需要运行一次证书管理工具以驱动证书信息出现,然后再更新控件。
   _FileWriteLog($hLogFile, "函数_Get_Key读取U-KEY证书信息失败,开始刷新证书信息!")
   If Not ProcessExists(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具"))) Then
    Local $iRunDBTool = Run($DBTool_SPDB, "", @SW_MINIMIZE)
    If @error Then
     _FileWriteLog($hLogFile, "刷新证书信息失败,失败类型: " & @error)
    Else
     _FileWriteLog($hLogFile, "刷新证书信息成功,进程标识符: " & $iRunDBTool)
    EndIf
   EndIf
   WinWait("浦发银行U-KEY管理工具", "", 10)
   Do ;这里如果不做循环等待,可能会出现不能关闭窗口进程的情况。
    If WinExists("浦发银行U-KEY管理工具") Then
     ProcessClose(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具")))
    EndIf
   Until Not ProcessExists(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具")))
   Local $i_Get_Key = _Get_Key() ;运行证书管理工具之后,如果此时系统没有硬件发生变动, _Get_Key()不会在执行了,所以还是读取不到证书的信息,所以这里必须再运行一次 _Get_Key()函数。
   If $i_Get_Key > 6 Then
       _FileWriteLog($hLogFile, "函数 _Get_Key读取U-KEY证书信息成功!")
    _FileWriteLog($hLogFile, "开始更新控件数据!")
   EndIf 
   If _GUICtrlListView_GetItemCount($idListview) = 0 Then
       _Key_GuiSetData()
    If _GUICtrlListView_GetItemCount($idListview) > 0 Then
        _FileWriteLog($hLogFile, "更新控件数据成功!")
       EndIf 
   EndIf 
  EndIf
 ElseIf StringLen(_Det_HardID()) < 6 Then
  _FileWriteLog($hLogFile, "函数_Det_HardID读取设备实例路径(ID)失败!")
  If StringLen(_Get_Key()) < 6 Then ;如果检测不到设备实例ID,也检测不到证书,说明U盾已拔除,并且系统中没有残留证书信息,直接更新控件。
   _FileWriteLog($hLogFile, "函数_Get_Key读取U-KEY证书信息失败!")
   _FileWriteLog($hLogFile, "开始更新控件数据!")
   _NoKey_GuiSetData()
   If _GUICtrlListView_GetItemCount($idListview) = 0 Then
    _FileWriteLog($hLogFile, "更新控件数据成功!")
   EndIf
  ElseIf StringLen(_Get_Key()) > 6 Then ;如果不能检测到设备实例ID,但是能检测到证书,说明证书信息残留在系统中,因此需要运行一次证书管理工具,然后再更新控件。
   _FileWriteLog($hLogFile, "函数_Get_Key读取U-KEY证书信息成功,开始刷新证书信息!")
   If Not ProcessExists(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具"))) Then
    Local $iRunDBTool = Run($DBTool_SPDB, "", @SW_MINIMIZE)
    If @error Then
     _FileWriteLog($hLogFile, "刷新证书信息失败,失败类型: " & @error)
    Else
     _FileWriteLog($hLogFile, "刷新证书信息成功,进程标识符: " & $iRunDBTool)
    EndIf
   EndIf
   WinWait("浦发银行U-KEY管理工具", "", 10)
   Do ;这里如果不做循环等待,可能会出现不能关闭窗口进程的情况。
    If WinExists("浦发银行U-KEY管理工具") Then
     ProcessClose(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具")))
    EndIf
   Until Not ProcessExists(WinGetProcess(WinGetHandle("浦发银行U-KEY管理工具")))
   $i_Get_Key = _Get_Key() ;运行证书管理工具之后,如果此时系统没有硬件发生变动, _Get_Key()不会在执行了,所以还是能读取到残留的证书信息,所以这里必须再运行一次 _Get_Key()函数。
   If $i_Get_Key < 6 Then
       _FileWriteLog($hLogFile, "函数 _Get_Key读取U-KEY证书信息失败!")
    _FileWriteLog($hLogFile, "开始更新控件数据!")
   EndIf
   _NoKey_GuiSetData()
   If _GUICtrlListView_GetItemCount($idListview) = 0 Then
    _FileWriteLog($hLogFile, "更新控件数据成功!")
   EndIf 
  EndIf
 EndIf
 $js_UKEY += 1
 ToolTip($js_UKEY, 1200, 300)
 Return $GUI_RUNDEFMSG
EndFunc   ;==>_U_KEY_Monitor

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-12-22 16:34 , Processed in 0.090176 second(s), 20 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表