Jump to content

GUIRegisterMsg and COM Object conflict...


Go to solution Solved by hname,

Recommended Posts

Posted

 

Hello,

Could anyone know why this code have following error. 

Quote

"C:\HTHSystem\Runtime\testdevice4.au3" (20) : ==> Variable must be of type "Object".:
$colitems = $objwmiservice.execquery("SELECT * FROM Win32_PnPEntity where Name LIKE '%Apple%' or Name Like '%adb%'")
$colitems = $objwmiservice^ ERROR
->11:19:31 AutoIt3.exe ended.rc:1

If I run the code without GUIRegisterMsg($WM_DEVICECHANGE , "WM_DEVICECHANGE") or DeviceList(), it works fine. My idea is to use GUIRegisterMsg  to detect any device event and then run DeviceList to find out which deviceID plug in. I can use only DeviceList() but it would require I run this function every 100 ms for detecting new devices.

Thanks.

 

$DBT_DEVNODES_CHANGED = 0x0007
$WM_DEVICECHANGE = 0x0219

Opt("GuiOnEventMode", 1)
$hWnd = GUICreate("", 500, 120)
GUISetState()
GUIRegisterMsg($WM_DEVICECHANGE , "WM_DEVICECHANGE")

While 1
    Sleep(100)
WEnd

Func WM_DEVICECHANGE($hWnd, $Msg, $wParam, $lParam)
    If $wParam = $DBT_DEVNODES_CHANGED Then DeviceList()
EndFunc

Func DeviceList()
    Local $objwmiservice, $colitems
    $objwmiservice = ObjGet("winmgmts:\\localhost\root\CIMV2")
    $colitems = $objwmiservice.execquery("SELECT * FROM Win32_PnPEntity where Name LIKE '%Apple%' or Name Like '%adb%'")
    For $objitem In $colitems
        $sret = $objItem.DeviceID
           MsgBox(0,"",$sret)
         Next
EndFunc

 

Posted (edited)

I tested your code with my Win7 and AutoIt 3.3.16.0.  I am not able to reproduce your issue.  Everything went smoothly without any error (although I removed your where clause).  What is your environment ?

Edit : there is a MsgBox indirectly within your WinProc function.  As per MSDN (and help file), it is not recommended to have a blocking function inside a WinProc.  Maybe it could be the source of your issue.  You could replace the MsgBox by a ConsoleWrite, see if it solves your problem.  If it does and you still need a MsgBox, I suggest you create a GUICtrlCreateDummy() and send a message to it from the WinProc.

 

Edited by Nine
Posted

I removed msgbox (and even where condition in SQL query) in the DeviceList() Function. I also updated AutoIT to the newest version (AutoIt 3.3.16.0). I run the code on ThinkPad X1 Yoga Windows 10 Pro.

Still same error on another Windows 10 Pro Computer. I don't have Windows 7 to test it on. 

Posted (edited)

It may be a little bit of confused when I post this code without any example. Below is how I run it:

You need to have at least an android phone with Developer Mode on or an iPhone. You need to authorize the device connection when asked by your phone devices the first time to plug it in USB port.

First, run my code above.

Second, plug the phone in or remove it if it was plugged. The Error code will shown up

image.png.917c8b50f68c6e757eb8020712f617ed.png

 

If you did not plug the phone in or remove it, there's no device event change and of course no error.

If you removed the GUIRegisterMsg($WM_DEVICECHANGE , "WM_DEVICECHANGE"), and run DeviceList() only, there's no error.

That's why I suspect something went conflicted when use GUIRegisterMsg($WM_DEVICECHANGE , "WM_DEVICECHANGE"), and COM Object together.

Any help please. Otherwise, I have to use a While Loop to detect new devices every 100 ms.

Edited by hname
Private info
Posted (edited)

Did you try with other devices like keyboard, or USB memory key ?  Do you get also an error or is it only with your cellular phones ?  I cannot test it now on a Win10 and with an Android phone.  I'll see tomorrow if I can replicate your issue, otherwise it is going to be very hard for me to help you.

In the mean time, put a COM error handler and provide the error code, so we know a bit more why the statement is failing.

Also try running x64 and #RequireAdmin, see if those can change anything.

Edited by Nine
  • Solution
Posted (edited)

Thank you very much Nine. I found why the code have error:

From GUIRegisterMsg help page:

Quote

Warning: blocking of running user functions which executes window messages with commands such as "MsgBox()" can lead to unexpected behavior, the return to the system should be as fast as possible !!!

So If I put a delay 5000 ms in the if condtion

Func WM_DEVICECHANGE($hWnd, $Msg, $wParam, $lParam)
    If $wParam = $DBT_DEVNODES_CHANGED Then
        sleep(5000)
        $deviceID = DeviceList()
        MsgBox(0,"", $deviceID)
    EndIf
EndFunc

Then it works perfectly.  However, anything less than 5000 ms will give rise to the error.  I don't know the reason why but It could be from the Warning above, It is weird that I have to wait at least 5 seconds to call the WMI query. To skip this delay, I can put a Global Boolean variable in the WM_DEVICECHANGE function and run DeviceList() function whenever the boolean variable return TRUE. Solved.
 

Once again, thank you for your suggestion.

Edited by hname
Posted (edited)
10 hours ago, hname said:

the return to the system should be as fast as possible !!!

But you are delaying even more by putting a long Sleep and using MsgBox.  This is not a solution.  Like I told you previously, you should use a CtrlDummy and send a message to it.  From that control,  you can then wait as long as you want and use any blocking function as you wish to...

To understand why it is failing we would need to know the error causing it query to fail.  A COM error handler will capture the error code.

I was not able to replicate your issue on Win10.  Here the code that you should try to run :

 

#include <GUIConstants.au3>

Global Const $DBT_DEVNODES_CHANGED = 0x0007

Global $oErrorHandler = ObjEvent("AutoIt.Error", ErrorFunc)

Global $hWnd = GUICreate("")
Global $idDummy = GUICtrlCreateDummy()
GUIRegisterMsg($WM_DEVICECHANGE, WM_DEVICECHANGE)
GUISetState()

While True
  Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
      ExitLoop
    Case $idDummy
      ConsoleWrite("Message was sent" & @CRLF)
      DeviceList()
  EndSwitch
WEnd

Func WM_DEVICECHANGE($hWnd, $iMsg, $wParam, $lParam)
  If $wParam = $DBT_DEVNODES_CHANGED Then
    ConsoleWrite("Notification received" & @CRLF)
    GUICtrlSendToDummy($idDummy)
  EndIf
  Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_DEVICECHANGE

Func DeviceList()
  Local $objwmiservice, $colitems
  $objwmiservice = ObjGet("winmgmts:\\localhost\root\CIMV2")
  $colitems = $objwmiservice.execquery("SELECT * FROM Win32_PnPEntity where Name = 'Moto G Play'")
  For $objitem In $colitems
    MsgBox(0, "WMI", $objitem.Caption & @CRLF & $objItem.DeviceID)
  Next
EndFunc   ;==>DeviceList

Func ErrorFunc($oError)
  ConsoleWrite(@ScriptName & " (" & $oError.scriptline & ") : ==> COM Error intercepted !" & @CRLF & _
      @TAB & "err.number is: " & @TAB & @TAB & "0x" & Hex($oError.number) & @CRLF & _
      @TAB & "err.windescription:" & @TAB & $oError.windescription & @CRLF & _
      @TAB & "err.description is: " & @TAB & $oError.description & @CRLF & _
      @TAB & "err.source is: " & @TAB & @TAB & $oError.source & @CRLF & _
      @TAB & "err.helpfile is: " & @TAB & $oError.helpfile & @CRLF & _
      @TAB & "err.helpcontext is: " & @TAB & $oError.helpcontext & @CRLF & _
      @TAB & "err.lastdllerror is: " & @TAB & $oError.lastdllerror & @CRLF & _
      @TAB & "err.scriptline is: " & @TAB & $oError.scriptline & @CRLF & _
      @TAB & "err.retcode is: " & @TAB & "0x" & Hex($oError.retcode) & @CRLF & @CRLF)
EndFunc   ;==>ErrorFunc

 

Edited by Nine
Posted

Your code works very well. It's good to know that GUICtrlCreateDummy() trick can be used to call DeviceList() (which is better IMO) instead of using a Boolean variable as in my case.

Thanks for your code.

Regards, 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...