Jump to content
Sign in to follow this  
bowertom

How to enable menue option without MouseClick()

Recommended Posts

bowertom

Hi,

I was trying to do a script that automatically sets an menue option in another program, please see attached screenshot. I used "Au3Record" to record the mouse clicks, etc. "Au3Record" fails to get the right coordinates, it seems like the coordinates are mirrored on the diagonal screen axis: the programs' main window opens down right of the screen (standard), but the recorded "Au3REcord"-coordinates are in the upper left ("MouseClick("right",107,425,1)").

Is there a way to activate a menue option in a different or rather direct way than using the MouseXXX()-functions?

Regards

Tom

-----------------------------------------

AutoIT v3.3.8.1, Win7 Pro 64 Bit

Edited by bowertom

Share this post


Link to post
Share on other sites
bowertom

Thanks for your advice. But the attached screenshot from my first post is perhaps a bit misleading. It doesn't show a particular part from the system tray, it's the program itself.

Please take a look at the attached screenshot.

post-72980-0-42928700-1338316890_thumb.j

Share this post


Link to post
Share on other sites
lark

Try using the ControlClick function. Use the AutoIt Window Info tool to gather the information about the control, and use something like

ControlClick("Phoner", "Destination Number", "[CLASS:Button]", "secondary")

But then again, I have never tried to use that on the right-click menu button of a control. So you could find out how far up and over the menu button is from the actual control, and use ControlGetPos to get the x and y coords of the control. Let's say the menu button is 20 pixels over (x + 20) and 40 pixels up (y - 40). So you could try something like:

Global $avControl = ControlGetPos("Phoner", "Destination Number", "[CLASS:Button]", "secondary")
Global $iXPos = $avControl[0] + Floor($avControl[2] / 2)
Global $iYPos = $avControl[1] + Floor($avControl[3] / 2)

MouseClick("secondary", $iXPos, $iYPos)

Sleep(300)

MouseClick("primary", $iXPos + 20, $iYPos - 40)

Share this post


Link to post
Share on other sites
bowertom

Thanks a lot, I tried the _SendMessage() solution first. This is what I did:

1) Used Microsoft Spy++ to get the params for the WM_COMMAND (couldn't get it done with Winspector). Spy++ had a lot of output. I considered this to be the important one:

<00381> 00071B36 P WM_COMMAND wNotifyCode:0 (sent from a menu) wID:67

... furthermore Spy++ showed that "00071B36" is a handle of an instance of the "TPUtilWindow" class Phoner uses.

2) I used this AutoIT-Code for testing:

#include <SendMessage.au3>

_SendMessage(0x00071B36,0x0111,67,0)

... and this works great! Both to enable and disable the Phoner option.

But now I'm stuck as the handle of course changes with each start of the program. I read about the "get handle from classname", etc., but this didn't help because there are a lot of "TPUtilWindow" instances around (half a dozen from Phoner itself and a lot more e.g. from Skype).

Is there a way to get the actual "TPUtilWindow" window class handle within AutoIT?

Share this post


Link to post
Share on other sites
bowertom

Sorry, but I don't get the point in this. When I take a look at the WinGetHandle() function together with the "special title definition", I think (and may be wrong, most likely) that the only possibilities to get the correct handle are to pass ...

a ) TITLE

b ) CLASS

c ) TITLE and CLASS

d ) TITLE and CLASS and INSTANCE

e ) CLASS and INSTANCE

... to the WinGetHandle() function. The problem now with a), c) and d) is, that these instances of the "TPUtilWindow" class do not have any titles and are invisible ("TPUtilWindow is used by components that require a window handle but have no windows" is what says another website about the "TPUtilWindow" class). Obviously b ) will not work, too, because the class is commonly used, so hitting the right "TPUtilWindow" instance would probably be impossible. Same with e).

Perhaps there's another approach? Because the WM_COMMAND method seems to be the "cleanest" solution and I don't yet want to let it go ;)

Share this post


Link to post
Share on other sites
Zedna

You can also use second parameter of WinGetHandle() - Text

EDIT:

You can also write your own helper routine which will for example analyze all children windows/controls and their properties/texts in all Windows with the same ClassName to distinguish among them.

Edited by Zedna

Share this post


Link to post
Share on other sites
bowertom

... ok, I finally managed it ;) Though it's probably not the best performing code, it does its' job.

/edit 1: Version 0.2 ... The option wasn`t activated in 1 out of 10 cases, because the program needs a bit of extra time afer start to create all TPUtilWindow-class instances. Added a 5 sec. sleep, now it works 100%.

/edit 2: The option is turned on and off the same way, so if you start the script twice it will turn off the option again and vice versa.

#include <SendMessage.au3>

Global Const $PhonerPath = "C:Program Files (x86)Phonerphoner.exe";Path to the Phoner executable


$pid = RunPhoner()
sleep(5000) ; Phoner needs a bit of extra time during startup to create all TPUtilWindow-class instances.
EnableOption($pid);Go for it


;---------------------------------Functions---------------------------------

;Returns Phoner PID. If Phoner is not running we start it
Func RunPhoner()
    Local $pid = ProcessExists("phoner.exe")
    
    If $pid == 0 Then;Phoner is not running, we start it now and return the PID
        $pid = Run($PhonerPath)
        
        If @error Then
            ShowErrorAndExit("Could not start Phoner.")
        ElseIf WinWait("Phoner", "", 10) == 0 Then
            ShowErrorAndExit("The Phoner main window did not show up.")
        Else
            Return $pid
        EndIf
    
    Else;Phoner is already running so we return the PID
        Return $pid
    EndIf
EndFunc

;Activate the Option in Phoner
Func EnableOption($pid)
    Local $phoner_pid = $pid
    Local $window_pid = ""
    
    If $phoner_pid == "" OR $phoner_pid < 0 Then
        ShowErrorAndExit("There was no or no correct Phoner PID passed to the function.")
    EndIf
    
    Local $WList_all_TPUtilWindows = WinList("[CLASS:TPUtilWindow]");First we get all window instances based on the TPUtilWindow class
    
    If $WList_all_TPUtilWindows[0][0] > 0 Then;Now we check for each window if it belongs to Phoner 
        For $i = 1 To $WList_all_TPUtilWindows[0][0]
            
            $window_pid = WinGetProcess($WList_all_TPUtilWindows[$i][1])
            
            If $window_pid < 0 Then
                ShowErrorAndExit("Could not retrieve PID from window handle.")
            Else
                If $window_pid == $phoner_pid Then ;we found a window that belongs to Phoner
                    _SendMessage($WList_all_TPUtilWindows[$i][1],0x0111,67,0);firing WM_COMMAND with corresponding wID. As there`s no return code or anything else, we neither need any error checking nor can we find out if the command hit the right class-instance, so we have to use brute force and send our WM_COMMAND to every window found
                EndIf
            EndIf
        Next
    Else
        ShowErrorAndExit("No TPUtilWindow-class windows were found.")
    EndIf
EndFunc

;Show MessageBox with an error text and exit the script
Func ShowErrorAndExit($text)
    MsgBox(0, "Error", $text)
    Exit
EndFunc

... the function described in one sentence is: get all TPUtilWindow based windows, check which of these windows belong to our program, then send the WM_COMMAND to those windows. This is kind of brute force, but there seems to be no way how the right TPUtilWindow instance could be triggered directly, because there's no titel, no text, nothing. So, for now I'm really happy with the actual solution, but if someone knows a better way ... you're welcome.

Thanks again to everyone!

Regards

Tom

Edited by bowertom

Share this post


Link to post
Share on other sites

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
Sign in to follow this  

×