Board index » cppbuilder » "use" menu item in another app?

"use" menu item in another app?


2005-05-17 04:58:19 PM
cppbuilder58
Hello. I can get a hold of a menu in another app just fine, like this:
HWND hwnd = NULL;
char buff[101];
hwnd = FindWindowEx(NULL, hwnd, NULL, "Target App");
HMENU hmenu = GetMenu(hwnd);
MENUITEMINFO menuinfo;
memset(&menuinfo, 0, sizeof(menuinfo));
menuinfo.cbSize = sizeof(MENUITEMINFO);
menuinfo.fMask = MIIM_STRING;
menuinfo.dwTypeData = NULL;
GetMenuItemInfo(hmenu, 2, true, &menuinfo);
menuinfo.dwTypeData = buff;
if (GetMenuItemInfo(hmenu, 2, true, &menuinfo))
ShowMessage(String(buff));
This gets me the caption of the item, but how to I simulate a click?
I've been looking through the WinAPI docs all day to no avail.
Thanks for any help.
P.S. My code example is my rough draft. I have never done any thing like
this - tapping into another app's menu - if there is any way to better
the code I put forth above please feel free to make corrections I need
all the good advice and help I can get :-)
 
 

Re:"use" menu item in another app?

Segal wrote:
Quote
hwnd = FindWindowEx(NULL, hwnd, NULL, "Target App");

MENUITEMINFO menuinfo;
if (GetMenuItemInfo(hmenu, 2, true, &menuinfo))

This gets me the caption of the item, but how to I simulate a click?
I'm not certain, but it looks like what you want is the wID member of
menuinfo.
Then just PostMessage( hwnd, WM_COMMAND, menuinfo.wID, 0);
 

Re:"use" menu item in another app?

"Bob Gonder" < XXXX@XXXXX.COM >wrote in message
Quote
Then just PostMessage( hwnd, WM_COMMAND, menuinfo.wID, 0);
Small change:
SendMessage( hWnd, WM_COMMAND, MAKEWPARAM(menuinfo.wID, 0), 0) );
Gambit
 

{smallsort}

Re:"use" menu item in another app?

Remy Lebeau (TeamB) wrote:
Quote
"Bob Gonder" wrote in message

>Then just PostMessage( hwnd, WM_COMMAND, menuinfo.wID, 0);

Small change:

SendMessage( hWnd, WM_COMMAND, MAKEWPARAM(menuinfo.wID, 0), 0) );
I was thinking Post was better than Send because you don't know what
the other application is going to do with the message, or how long it
will take to process it. And if it hangs while processing, won't your
app hang too?
 

Re:"use" menu item in another app?

Bob Gonder wrote:
Quote
Remy Lebeau (TeamB) wrote:

>"Bob Gonder" wrote in message
>
>>Then just PostMessage( hwnd, WM_COMMAND, menuinfo.wID, 0);
>
>Small change:
>
>SendMessage( hWnd, WM_COMMAND, MAKEWPARAM(menuinfo.wID, 0), 0) );

I was thinking Post was better than Send because you don't know what
the other application is going to do with the message, or how long it
will take to process it. And if it hangs while processing, won't your
app hang too?
Than kfor all the repsonses, but neither of those seem to work:
HWND hwnd = NULL;
char buff[101];
// App with Menu
hwnd = FindWindowEx(NULL, hwnd, NULL, "Target App");
HMENU hmenu = GetMenu(hwnd); // Main menu
MENUITEMINFO menuinfo;
memset(&menuinfo, 0, sizeof(menuinfo));
menuinfo.cbSize = sizeof(MENUITEMINFO);
menuinfo.fMask = MIIM_STRING;
menuinfo.dwTypeData = NULL;
// 3rd menu (to right of File menu - File | Edit | Options -
// gettign the Options menu.)
GetMenuItemInfo(hmenu, 2, true, &menuinfo);
menuinfo.dwTypeData = buff;
if (GetMenuItemInfo(hmenu, 2, true, &menuinfo)) {
ShowMessage(String(buff)); // Returns "Option"
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(menuinfo.wID, 0), 0);
PostMessage( hwnd, WM_COMMAND, menuinfo.wID, 0);
}
Either method doesn't seem to do anything.
P.S.
As a little side question, I noticed the String I get (the Menu-item
caption) always is short a caracter on the end when it has an underlined
(shortcut) char. Is this a known bug (looks like it doesn't count the
hidden '&' when counting how many chars and ends up 1 char short in
length, hence lopping the last one off. Such as above getting "Option"
with underlined 'O' instead of "Options".)
 

Re:"use" menu item in another app?

"Segal" < XXXX@XXXXX.COM >wrote in message
Quote
Than kfor all the repsonses, but neither of those seem to work:
Then you are not using it properly, because WM_COMMAND *is* the proper way
that menu item clicks are issued.
Quote
hwnd = FindWindowEx(NULL, hwnd, NULL, "Target App");
You are not verifying that hwnd is not NULL before using it.
Quote
HMENU hmenu = GetMenu(hwnd); // Main menu
You are not verifying that hmenu is not NULL before using it.
Quote
menuinfo.fMask = MIIM_STRING;
MIIM_STRING is not a valid entry for the fMask member. It is used with the
fType member instead. You should be specifying the MIIM_TYPE mask instead.
Also, you are trying to retrieve the menu item's ID, but you did not specify
the MIIM_ID mask at all.
Quote
menuinfo.dwTypeData = NULL;
To retreive the menu item text, you need to provide your own buffer for the
text to be stored into. NULL is not valid, and you must also fill in the
cch member as well so the menu knows how large the buffer is.
Quote
GetMenuItemInfo(hmenu, 2, true, &menuinfo);
menuinfo.dwTypeData = buff;
if (GetMenuItemInfo(hmenu, 2, true, &menuinfo)) {
Why are you calling GetMenuItemInfo() twice?
Quote
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(menuinfo.wID, 0), 0);
PostMessage( hwnd, WM_COMMAND, menuinfo.wID, 0);
Why are you issuing the WM_COMMAND message twice?
Quote
Either method doesn't seem to do anything.
That is because you are not retreiving the menu item ID properly in the
first place.
With all of that said, you need to use the following code instead:
HWND hwnd = NULL;
char buff[101] = {0};
// App with Menu
hwnd = FindWindowEx(NULL, hwnd, NULL, "Target App");
if( hwnd )
{
HMENU hmenu = GetMenu(hwnd); // Main menu
if( hmenu )
{
MENUITEMINFO menuinfo = {sizeof(MENUITEMINFO), 0};
menuinfo.fMask = MIIM_ID | MIIM_TYPE;
menuinfo.dwTypeData = buff;
menuinfo.cch = 100;
if( GetMenuItemInfo(hmenu, 2, TRUE, &menuinfo) )
{
ShowMessage(buff);
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(menuinfo.wID, 0),
0);
}
}
}
Quote
As a little side question, I noticed the String I get (the Menu-item
caption) always is short a caracter on the end when it has an underlined
(shortcut) char. Is this a known bug (looks like it doesn't count the
hidden '&' when counting how many chars and ends up 1 char short in
length, hence lopping the last one off. Such as above getting "Option"
with underlined 'O' instead of "Options".)
Gambit
 

Re:"use" menu item in another app?

Remy Lebeau (TeamB) wrote:
Quote
"Segal" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...
With all of that said, you need to use the following code instead:

HWND hwnd = NULL;
char buff[101] = {0};

// App with Menu
hwnd = FindWindowEx(NULL, hwnd, NULL, "Target App");
if( hwnd )
{
HMENU hmenu = GetMenu(hwnd); // Main menu
if( hmenu )
{
MENUITEMINFO menuinfo = {sizeof(MENUITEMINFO), 0};
menuinfo.fMask = MIIM_ID | MIIM_TYPE;
menuinfo.dwTypeData = buff;
menuinfo.cch = 100;

if( GetMenuItemInfo(hmenu, 2, TRUE, &menuinfo) )
{
ShowMessage(buff);
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(menuinfo.wID,
0), 0);
}
}
}
Thanks a lot REmy this worked wel. I had been following an example on I
found on google group that apparently wasn't well made :P
I have one more little question though.
The "click" on the menu item works and a message box opos up. I cna get
it's HWND just fine and put text in the text-boxes just fine, how ever,
the "OK" button is grayed out and wont respon d to BM_CLICK. If I
manaully go to said message box with my mouse and manually type a
character in the field it enables the button. But it doesn't enable it
when I insert text from my program.
Is there any way to either "enable" the button using WINAPI (I looked
through SDK help file but could not find anything) or send a message to
make it think actual typing has occured that trigers the enabling of the
button.
BtnHwnd = FindWindowEx(hwnd, NULL, "CRolloverButton", "&Send");
ShowMessage(String().sprintf("Send Button: 0x%08X", BtnHwnd));
SendMessage(BtnHwnd, BM_CLICK, NULL, NULL);
BtnHwnd in the ShowMessage box is non zero so it looks like it find it
right, though if I replace "&Send" with "&Cancel", which is not
disabled, that doesn't seem to work (the box doesn't close.)
Is is possible that BM_CLICK is being ignored?
Thanks again.
 

Re:"use" menu item in another app?

Remy Lebeau (TeamB) wrote:
Since the goal was to click the menu item,
this could be further simplified.
Quote
HWND hwnd = NULL;
char buff[101] = {0};

// App with Menu
hwnd = FindWindowEx(NULL, hwnd, NULL, "Target App");
if( hwnd )
{
HMENU hmenu = GetMenu(hwnd); // Main menu
if( hmenu )
{
UINT id = GetMenuItemID( hmenu, 2 );
if( id != 0xFFFFFFFF )
{
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM( id, 0),0);
// MessageBox( 0, "MessageSent","MyApp",MB_OK);
}else{
// it is a sub-menu or not a command
Quote
}
}
}
Can also use GetMenuString() to get the text.
Quote
>As a little side question, I noticed the String I get (the Menu-item
>caption) always is short a caracter on the end when it has an underlined
Remy mentioned your incorrect use of cch. That's likely the cause.
 

Re:"use" menu item in another app?

Bob Gonder wrote:
Quote
Remy Lebeau (TeamB) wrote:

Since the goal was to click the menu item,
this could be further simplified.

>HWND hwnd = NULL;
>char buff[101] = {0};
>
>// App with Menu
>hwnd = FindWindowEx(NULL, hwnd, NULL, "Target App");
>if( hwnd )
>{
>HMENU hmenu = GetMenu(hwnd); // Main menu
>if( hmenu )
>{
UINT id = GetMenuItemID( hmenu, 2 );
if( id != 0xFFFFFFFF )
{
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM( id, 0),0);
// MessageBox( 0, "MessageSent","MyApp",MB_OK);
}else{
// it is a sub-menu or not a command
>}
>}
>}

Can also use GetMenuString() to get the text.

>>As a little side question, I noticed the String I get (the Menu-item
>>caption) always is short a caracter on the end when it has an
>>underlined

Remy mentioned your incorrect use of cch. That's likely the cause.
Yes that was the cause. It how gets the whole string instead of being 1
short. I originally got that code from an example I found on google
group somewhere, which evidently was incorrect.
 

Re:"use" menu item in another app?

Segal wrote:
Quote
Is there any way to either "enable" the button using WINAPI

BtnHwnd = FindWindowEx(hwnd, NULL, "CRolloverButton", "&Send");
EnableWindow( BtnHwnd, TRUE );
Quote
SendMessage(BtnHwnd, BM_CLICK, NULL, NULL);

Is is possible that BM_CLICK is being ignored?
Yes, if the app keeps track of it internally.
You might need to send WM_KEYDOWN and WM_KEYUP events to the edit box
so that it unlocks the Ok button.
 

Re:"use" menu item in another app?

"Segal" < XXXX@XXXXX.COM >wrote in message
Quote
how ever, the "OK" button is grayed out and wont respon d to
BM_CLICK. If I manaully go to said message box with my
mouse and manually type a character in the field it enables the
button. But it doesn't enable it when I insert text from my program.
You did not show how you are filling in the dialog exactly. Apparently, the
dialog expects individual characters to be typed, but without seeing your
actual code, I would guess that you are not simulating any typing at all,
just assigning the text in full, which the dialog is not coded to handle the
same way.
Quote
Is is possible that BM_CLICK is being ignored?
Possibly. MSDN says the following:
"If the button is in a dialog box and the dialog box is not active, the
BM_CLICK message might fail. To ensure success in this situation, call the
SetActiveWindow function to activate the dialog box before sending the
BM_CLICK message to the button."
Have you tried sending a WM_COMMAND/BN_CLICKED message to the dialog rather
than sending BM_CLICK to the button?
Gambit
 

Re:"use" menu item in another app?

Remy Lebeau (TeamB) wrote:
Quote
"Segal" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...

>how ever, the "OK" button is grayed out and wont respon d to
>BM_CLICK. If I manaully go to said message box with my
>mouse and manually type a character in the field it enables the
>button. But it doesn't enable it when I insert text from my program.

You did not show how you are filling in the dialog exactly.
Apparently, the dialog expects individual characters to be typed, but
without seeing your actual code, I would guess that you are not
simulating any typing at all, just assigning the text in full, which
the dialog is not coded to handle the same way.
My apologies.
// First text field (both text fields are of class "Edit".)
HWND EditHwnd = FindWindowEx(hwnd, EditHwnd, "Edit", NULL);
if (!EditHwnd) return;
SendMessage(EditHwnd, WM_SETTEXT, (WPARAM)50,
(LPARAM)SingleLine->Text.c_str());
// 2nd text field.
EditHwnd = FindWindowEx(hwnd, EditHwnd, "Edit", NULL);
if (!EditHwnd) return;
SendMessage(EditHwnd, WM_SETTEXT, (WPARAM)50,
(LPARAM)MultiLine->Lines->Text.c_str());
Quote
>Is is possible that BM_CLICK is being ignored?

Possibly. MSDN says the following:

"If the button is in a dialog box and the dialog box is not
active, the BM_CLICK message might fail. To ensure success in this
situation, call the SetActiveWindow function to activate the dialog
box before sending the BM_CLICK message to the button."

Have you tried sending a WM_COMMAND/BN_CLICKED message to the dialog
rather than sending BM_CLICK to the button?
I just tried both
SendMessage(hwnd, WM_COMMAND, 0, 0);
and
SendMessage(hwnd, BN_CLICKED, 0, 0);
I even tried
EnableWindow(hwnd, TRUE);
before both of those calls and it still doesn't submit the box (as if
"OK" is clicked.) If I try using the Cancel button intead it doesn't
work either. The box just stays there. If I manually click either button
they work fine.
 

Re:"use" menu item in another app?

"Segal" < XXXX@XXXXX.COM >wrote in message
Quote
SendMessage(EditHwnd, WM_SETTEXT, (WPARAM)50,
(LPARAM)SingleLine->Text.c_str());
As I suspected, you are not simulating any typing at all.
Also, why are you specifying a value for the WPARAM of the message?
WM_SETTEXT doesn't use the WPARAM at all.
Quote
I just tried both

SendMessage(hwnd, WM_COMMAND, 0, 0);
Make sure that you are sending WM_COMMAND to the dialog itself, not the
button. Also, you are not specifying BN_CLICKED at all.
WORD wID = GetDlgCtrlID(EditHwnd);
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(wID, BN_CLICKED), (LPARAM)
EditHwnd);
Quote
SendMessage(hwnd, BN_CLICKED, 0, 0);
BN_CLICKED is not a standalone message. You must send it via WM_COMMAND.
Quote
before both of those calls and it still doesn't submit the box (as if
"OK" is clicked.)
You are not sending the messages correctly to begin with, so it won't matter
whether you enable the button or not.
Gambit
 

Re:"use" menu item in another app?

Remy Lebeau (TeamB) wrote:
Quote
"Segal" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...

>SendMessage(EditHwnd, WM_SETTEXT, (WPARAM)50,
>(LPARAM)SingleLine->Text.c_str());

As I suspected, you are not simulating any typing at all.

Also, why are you specifying a value for the WPARAM of the message?
WM_SETTEXT doesn't use the WPARAM at all.

>I just tried both
>
>SendMessage(hwnd, WM_COMMAND, 0, 0);

Make sure that you are sending WM_COMMAND to the dialog itself, not
the button. Also, you are not specifying BN_CLICKED at all.

WORD wID = GetDlgCtrlID(EditHwnd);
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(wID, BN_CLICKED), (LPARAM)
EditHwnd);

>SendMessage(hwnd, BN_CLICKED, 0, 0);

BN_CLICKED is not a standalone message. You must send it via
WM_COMMAND.

>before both of those calls and it still doesn't submit the box (as if
>"OK" is clicked.)

You are not sending the messages correctly to begin with, so it won't
matter whether you enable the button or not.
Thank you very much for pointing out my mistakes. I'm trying to get more
used ot working with the winapi.
Your code,
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(wID, BN_CLICKED),
(LPARAM) EditHwnd);
works perfectly. Thank you again.