News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

click on menu item of another app

Started by Jimg, September 16, 2005, 03:26:41 PM

Previous topic - Next topic

Jimg

I have a commercial application that I need to use many times every day.  It's a good app, but the user interface could use some help.  What I would like to do is write a program that would send a clicked message to one of the menu items and then one of the sub-menu items.  I've already figured out how to move the pop-ups around, I just can't seem to find the menu ids.  I'm sure I've seen this topic addressed before, but I'm having no luck finding the topic.  Reshacker was no help as it says the app was compressed.  How does one find the menu ids of a running app?  I thought about sending a mouse message but the I move the window around sometimes so the mouse coordinates wouldn't be the same, and it seems like just sending a WM_COMMAND with the id would be better.  No?

AeroASM

There is a tool called Spy++ which lets you monitor, among other things, window messages. Start up Spy++ and monitor the window of your application, then click on a menu item and SPy++ will show the details of the message, which will contain the menu ID. In fact the details of the message will be the same ones that you need to send yourself.

Jimg

Thank you, but I do not now nor do I ever intend to own C++

AeroASM

But Spy++ is nothing to do with C++. How did you come to that conclusion?

Jimg

Hmmmm-  I googled and everything came up that it was part of c++ or possibly visual studio?  I'll go look again.

Jimg

Yup.  Definately part of visual studio.  I'll unpack my old vb6 disks to see if it's on there.

Later....

I'll be darned.  It was on there.  Thanks for the tip :P

P1

Quote from: Jimg on September 16, 2005, 08:07:43 PM
Yup.  Definately part of visual studio.  I'll unpack my old vb6 disks to see if it's on there.
Nope.

I got mine off a Learning Edition of VC++  v6.  Which was with a game programming book for free.  Never used the C stuff, but I used everyting else for MASM developement.   :toothy

Regards,  P1  :8)

Jimg

Wow, that was sure entertaining and enlightening.

I look like the message to send is

WM_SYSCOMMAND uCmdType:SC_MOUSEMENU xPos:553 yPos:26

I would have never thought to do such a thing ::)

Does this sound reasonable to anyone??

Jimg

Well, that kept me entertained for hours, but produced absolutely no results.  Surely this is something that is done all the time, one of those well known things that I just haven't had to do yet.  What's the secret????  Would it be better to try to send a keystroke?  How do you send an alt-p to an app??  It's not a normal wm_char type thing.

Jimg

Ok, let's try this a different way.  Does anybody see why this code wouldn't click the menu items in the other app?

.data
CurrWnd   dd 0
TaskName  db 100 dup (0)
MedVed    db 'Default Portfolio - Medved QuoteTracker',0
hMedVed   dd 0
MedVedPid dd 0
ThisPid   dd 0
.code
Doit proc
    inv GetWindow,hWin,GW_HWNDFIRST
    mov CurrWnd,eax
DoitLoop:
    cmp eax,0
    je DoitDone
    inv GetParent,eax
    inv GetWindowTextLength,CurrWnd
    .if eax>0
        inv GetWindowText,CurrWnd,addr TaskName,99
        PrintString TaskName
        mov ecx,offset TaskName
        mov edx,offset MedVed
    @@:
        mov al,[edx]
        cmp al,0
        je @f       ; good
        cmp al,[ecx]
        jne ng
        inc ecx
        inc edx
        jmp @b
    @@:

        mov eax,CurrWnd
        mov hMedVed,eax
        PrintHex hMedVed

        inv GetWindowThreadProcessId,hMedVed,ADDR MedVedPid
        inv GetCurrentThreadId
        mov ThisPid, eax
        inv AttachThreadInput, ThisPid, MedVedPid, TRUE
        inv SetForegroundWindow,hMedVed
        inv Sleep,500
        inv SendMessage,hMedVed, WM_SYSKEYDOWN, 50h,20190001h  ; 'alt-p'
        inv Sleep,500
        inv SendMessage,hMedVed, WM_SYSKEYUP,   50h,0e0190001h
        inv Sleep,500
        inv SendMessage,hMedVed, WM_SYSKEYDOWN, 45h,20120001h   ; 'alt-e'
        inv Sleep,500
        inv SendMessage,hMedVed, WM_SYSKEYUP,   45h,0E0120001h
        inv Sleep,500
               
        inv AttachThreadInput,ThisPid,MedVedPid,FALSE
        ret ; done
    .endif
    ng:
    inv GetWindow,CurrWnd,GW_HWNDNEXT
    mov CurrWnd,eax
    jmp DoitLoop
       
DoitDone:
    ret
Doit EndP


I know I have the right handle because the app get the focus.

farrier

#10
Jimg,

I have done a similar thing, but instead of using "inv SendMessage"

I used:
push eax
invoke keybd_event, eax, NULL, NULL, NULL                   ;Press key
invoke Sleep, 200
pop eax                                                      ;Get the same key from stack
invoke keybd_event, eax, NULL, KEYEVENTF_KEYUP, NULL        ;Release key


hth,

farrier
It is a GOOD day to code!
Some assembly required!
ASM me!
With every mistake, we must surely be learning. (George...Bush)

Jimg

Excellent!  That actually worked!  I've got a little cleanup to do, for some reason the alt key gets stuck down ::)

Thank you very much farrier.

farrier

Jimg,

You are welcomed!

Also look here:

http://board.win32asmcommunity.net/index.php?topic=21503.0

Haven't tried this, but it sounds like the way to go, if you are starting up the other program!

hth,

farrier
It is a GOOD day to code!
Some assembly required!
ASM me!
With every mistake, we must surely be learning. (George...Bush)

Jimg

#13
Everything is working except restoring the app if it is minimized  (OpenIcon).  I also found that I didn't need any sleeps or the attachthread stuff.  Anyone know why OpenIcon is not restoring the window?  The return shows no error.

Here's the code so far, including the part that moves the window that pops up from the menu clicks-

.686p
.model  flat, stdcall
option  casemap :none   ; case sensitive
.nolist
include windows.inc

inv equ Invoke

uselib  MACRO   libname
    include     libname.inc
    includelib  libname.lib
ENDM
uselib user32
uselib kernel32
;uselib masm32
;uselib debug

.listall

.data?
Phase     dd ?
CurrWnd   dd ?
TaskName  db 100 dup (?)

.data
MedVed    db 'Default Portfolio - Medved QuoteTracker',0
PortFolio db 'Portfolios and Alerts',0

.code

Program:

    mov Phase,1

DoitStart:
    inv FindWindow,0,0      ; get starting window
    mov CurrWnd,eax

DoitLoop:
    cmp eax,0
    je DoitDone
    inv GetWindowTextLength,CurrWnd
    .if eax>0
        inv GetWindowText,CurrWnd,addr TaskName,99
        ;PrintString TaskName
        mov ecx,offset TaskName
        .if Phase==1
            mov edx,offset MedVed
        .else
            mov edx,offset PortFolio
        .endif
    @@:
        mov al,[edx]    ; compare window found against what we want
        cmp al,0
        je @f           ; found all we wanted
        cmp al,[ecx]
        jne NextWindow  ; not this one, go look for next window name
        inc ecx
        inc edx
        jmp @b
    @@:
        .if Phase==1
            inv IsIconic,CurrWnd            ; if minimized
            .IF eax!=0
                inv OpenIcon,CurrWnd        ; restore
            .ENDIF
            inv SetForegroundWindow,CurrWnd
            inv keybd_event, VK_MENU, 0, 0, 0   ;Send Alt key 'down'
            inv Sleep, 40
            inv keybd_event, VK_P, 0, 0, 0 ;Send P key 'down'
            inv Sleep, 40           
            inv keybd_event, VK_P, 0, KEYEVENTF_KEYUP, 0 ;Send P key 'up'
            inv Sleep, 40
            inv keybd_event, VK_MENU, 0, KEYEVENTF_KEYUP, 0 ;Send Alt key 'up'
            inv Sleep, 40
            inv keybd_event, VK_E, 0, 0, 0 ;Send E key 'down'
            inv Sleep, 40
            inv keybd_event, VK_E, 0, KEYEVENTF_KEYUP, 0 ;Send E key 'up'
               
            inc Phase
            jmp DoitStart
        .else   ; Phase 2, move the window
            inv MoveWindow, CurrWnd, 425, 0, 600, 436, TRUE
            jmp DoitDone
        .endif
    .endif

NextWindow:
    inv GetWindow,CurrWnd,GW_HWNDNEXT
    mov CurrWnd,eax
    jmp DoitLoop
       
DoitDone:
    inv ExitProcess, 0

end Program


This is written as a console app, but I had to link it as a window to keep the console from flashing.

Edit:

I had to add the sleeps back in.  In some cases it was just too fast for the app to process.  I would have though these messages would have just stacked up to be processed whenever the app was ready, but it clearly has a problem at times.

farrier

Jimg,

Have you tried:

ShowWindow

with:

SW_RESTORE

Then:

SetForegroundWindow

hth,

farrier
It is a GOOD day to code!
Some assembly required!
ASM me!
With every mistake, we must surely be learning. (George...Bush)