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?
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.
Thank you, but I do not now nor do I ever intend to own C++
But Spy++ is nothing to do with C++. How did you come to that conclusion?
Hmmmm- I googled and everything came up that it was part of c++ or possibly visual studio? I'll go look again.
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
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)
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??
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.
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.
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
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.
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
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.
Jimg,
Have you tried:
ShowWindow
with:
SW_RESTORE
Then:
SetForegroundWindow
hth,
farrier
Yes, I did, but that didn't work either.
Jimg,
That seems to indicate that you don't have the correct hWnd !!!
Spy++ may be your best bet to find and compare the real hWnd with what you are using at the time.
hth,
farrier
The handle I'm finding is the same handle as Spy++, and everything else was working, so it should have been the correct handle anyway.
Looking a little more closely, I made some assumptions I shouldn't have. I knew that the app was iconic, I just minimized it myself. The IsIconic api, however, returned false. So I wasn't really executing the openicon api. When I forced the OpenIcon call, it restored the app to normal. The wierd thing, however, is that afterward, I could not minimize the app again, the minimize button was just ignored. The same thing happened using showwindow. Obviously, I'm not doing this right. If I can't trust IsIconic, what do I use??
After some testing, I've determined that this app is just wierd. I tried the process on another app, and the isiconic and openicon worked properly. For some reason, when this app is minimized, it doesn't test as minimized, and a GetWindowRect shows the same coordinates, minimized or not, where a normal app shows minimize coordinates way off the screen as expected. Does anyone know what this effect is and how to handle it?
Is it 16bit Windows 3.1 app???
Regards, P1 :8)
No, not at all. http://www.quotetracker.com/
Quote from: farrier on September 18, 2005, 11:23:39 PM
SetForegroundWindow
There are some problems with SetForegroundWindow, check http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/windows/windowreference/windowfunctions/setforegroundwindow.asp
A safe way to activate a window is
inv ShowWindow, Handle, SW_HIDE ;optional, may be faster
inv ShowWindow, Handle, SW_MINIMIZE
inv ShowWindow, Handle, SW_RESTORE
Also if you didn't notice this already, each "press" of the ALT key must occur twice in code - one call for down, and one call for up. That's why it "sticks."