Jaymol
asked on
Another App's System Menu.
I have added a new menu item to another application. I now need to know how to handle it. Any suggestions?
How this was done ?
ASKER
Simple....
assume you have the handle of a running application and use the following code...(Hndl=handle)
var
SysMenu : HMenu;
begin
SysMenu:=GetSystemMenu(Hnd l, False);
AppendMenu(SysMenu, MF_SEPARATOR,
0, nil);
AppendMenu(SysMenu, MF_BYCOMMAND,
666, '&I made this...');
end;
There you go! Now, I need to be able to handle a click on that menu option.
John.
assume you have the handle of a running application and use the following code...(Hndl=handle)
var
SysMenu : HMenu;
begin
SysMenu:=GetSystemMenu(Hnd
AppendMenu(SysMenu, MF_SEPARATOR,
0, nil);
AppendMenu(SysMenu, MF_BYCOMMAND,
666, '&I made this...');
end;
There you go! Now, I need to be able to handle a click on that menu option.
John.
ASKER
Okay then...more points. (But no more.)
following..
Jaymol;
Really, poor points = Poor efforts
When the user click at your menu item, your form receive a WM_SYSCOMMAND, the LPARAM identifies the menu item selected.
Try to see the VCL to TMenuItem.AppendTo ( Private method ). It's a good sample to start.
T++, Radler.
Really, poor points = Poor efforts
When the user click at your menu item, your form receive a WM_SYSCOMMAND, the LPARAM identifies the menu item selected.
Try to see the VCL to TMenuItem.AppendTo ( Private method ). It's a good sample to start.
T++, Radler.
ASKER
Radler,
Really, bad reading = Bad answer
I'm attempting to trap the click event of a system menu on *another* application, say Microsoft Word, etc..
Not, the application I've written.
Ta,
John.
Really, bad reading = Bad answer
I'm attempting to trap the click event of a system menu on *another* application, say Microsoft Word, etc..
Not, the application I've written.
Ta,
John.
hi jaymol,
seems it is better to use insertmenuitem instead of appendmenu
the menuitem sends a message to its menu-owner, if its selected. this message you must get (hook?)
but maybe i'm wrong
meikl
seems it is better to use insertmenuitem instead of appendmenu
the menuitem sends a message to its menu-owner, if its selected. this message you must get (hook?)
but maybe i'm wrong
meikl
ASKER
That's what I'm asking
Jaymol
This is simple, when you create the menu item create a handler (user message) aswell and then trap the WM_SYSCOMMAND as radler mentioned...
add this to your private section
procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
{this is used to define our system message for the sytem menu item we create}
then create the handler
const
SC_RemoveTableHandler = WM_USER + 1;{this is the our system message ID}
then when you call your code...
procedure TChildFrm.FormCreate(Sende r: TObject);
var
SysMenu: HMenu;
begin
SysMenu := GetSystemMenu(Handle, False);//get the system menu handle
AppendMenu(SysMenu, MF_BYPOSITION or MF_SEPARATOR, 0, '');//add a separator first
AppendMenu(SysMenu, MF_BYPOSITION or MF_STRING, SC_RemoveTableHandler{your handler here}, 'Remove &Table');//add our menu item and pass the user defined message
{this is a hack and not really recommened by windows but poses no problems}
DeleteMenu(SysMenu, SC_CLOSE, MF_BYCOMMAND);
DeleteMenu(SysMenu, 6, MF_BYPOSITION);
end;
then when the System recieves this message do your stuff...
procedure TChildFrm.WMSysCommand(var Msg: TWMSysCommand);
begin
if Msg.CmdType = SC_RemoveTableHandler then begin {call the user defined system message}
{call our code here}
end
else
inherited;{this is very important, need for the rest of the system menu work as default}
end;
Later
BoRiS
This is simple, when you create the menu item create a handler (user message) aswell and then trap the WM_SYSCOMMAND as radler mentioned...
add this to your private section
procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
{this is used to define our system message for the sytem menu item we create}
then create the handler
const
SC_RemoveTableHandler = WM_USER + 1;{this is the our system message ID}
then when you call your code...
procedure TChildFrm.FormCreate(Sende
var
SysMenu: HMenu;
begin
SysMenu := GetSystemMenu(Handle, False);//get the system menu handle
AppendMenu(SysMenu, MF_BYPOSITION or MF_SEPARATOR, 0, '');//add a separator first
AppendMenu(SysMenu, MF_BYPOSITION or MF_STRING, SC_RemoveTableHandler{your
{this is a hack and not really recommened by windows but poses no problems}
DeleteMenu(SysMenu, SC_CLOSE, MF_BYCOMMAND);
DeleteMenu(SysMenu, 6, MF_BYPOSITION);
end;
then when the System recieves this message do your stuff...
procedure TChildFrm.WMSysCommand(var
begin
if Msg.CmdType = SC_RemoveTableHandler then begin {call the user defined system message}
{call our code here}
end
else
inherited;{this is very important, need for the rest of the system menu work as default}
end;
Later
BoRiS
I think Meikl was the closest here. Boris you gave the obvious solution which only works for an application to work with its own system menu.
As Meikl already mention (and I second) you need to get to the message which is sent to the application with the modified system menu. Unfortunately, you cannot redirect the window procedure of a window which does not belong to your process. So the only solution I can see here is to install a global hook and listen to all message for a specific window and handle accordingly.
How to install a system hook has been widely discussed here in the last weeks.
Ciao, Mike
As Meikl already mention (and I second) you need to get to the message which is sent to the application with the modified system menu. Unfortunately, you cannot redirect the window procedure of a window which does not belong to your process. So the only solution I can see here is to install a global hook and listen to all message for a specific window and handle accordingly.
How to install a system hook has been widely discussed here in the last weeks.
Ciao, Mike
Your answer Boris was exactly what I said, but Jaymol wanna another thing :-(
Windows will be send this message to Word, of course so your program can't take it.
A way is create a Hook to Trap all WM_S... and find these associated with Words instances.
T++, Radler.
Windows will be send this message to Word, of course so your program can't take it.
A way is create a Hook to Trap all WM_S... and find these associated with Words instances.
T++, Radler.
ASKER
Boris, isn't that only gonna work for MY application?
Lischke
Mmmm, I have not tested this on another sysem menu, so you may be very right...
Jaymol
This will at least give you a guide line once you trap the message sent by the menu item...
Sorry everyone I jumped the gun here, I'm in a rush to get home it's 6:00pm here...
Later
BoRiS
BTW Just reject the answer if it is of no use...
Mmmm, I have not tested this on another sysem menu, so you may be very right...
Jaymol
This will at least give you a guide line once you trap the message sent by the menu item...
Sorry everyone I jumped the gun here, I'm in a rush to get home it's 6:00pm here...
Later
BoRiS
BTW Just reject the answer if it is of no use...
ASKER
Thanks Boris, but you're right. It wasn't an answer to my question. If this is similar to an ongoing and unanswered question, I'll delete it in a day or so. Never mind. :-(
you should create a DLL and hook it... it's pretty easy... you'll receive a WM_COMMAND message when a menu item is clicked... then you can check out the wParam to get the menu item's ID...
..-=ViKtOr=-..
..-=ViKtOr=-..
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Dragon, I can tell you why your code crashs and it is rather strange that it runs at all. First, you have declared global variables (HookSet, HookHandle etc.). These variables are only valid in the process which installed the hook and filled them. But your hook will be called in the context of the process for which a particular message is sent. You need to store the vars in a memory mapped file...
The second problem is your self defined message. This might be valid for your application alone, but not for all others. It may well be that this ID is almost used by other apps. hence you need to correctly register an own message.
Ciao, Mike
The second problem is your self defined message. This might be valid for your application alone, but not for all others. It may well be that this ID is almost used by other apps. hence you need to correctly register an own message.
Ciao, Mike
ASKER
DragonSlayer: Thanks for the code. Wonderful!!! Regarding the fact that it runs on NT but crashes on 95/98....I have quite a few components on my website, and I program in NT. I've had a few people come back to me and tell me that they've had problems running them on 95 or 98. What's going on???
John.
John.
ASKER
DragonSlayer : One question though....What should I use insted of MF_MOUSESELECT to identify a click? (That detects the mouse being over it!)
Ta,
John.
Ta,
John.
ASKER
Will somebody PLEASE give me a clue?
Sorry there Jaymol,
Was quite busy one whole day...
Will MF_SYSMENU work then? Don't have time to try it out myself, sorry... the project manager's gonna kill me if I delay the project any longer :)
Cheers,
DragonSlayer
Was quite busy one whole day...
Will MF_SYSMENU work then? Don't have time to try it out myself, sorry... the project manager's gonna kill me if I delay the project any longer :)
Cheers,
DragonSlayer
ASKER
This doesn't make any difference - unless of course I've done it wrong! I simply replaced the MF_MOUSESELECT with MF_SYSMENU, but it was still the same! Any other suggestions?
John.
John.
Experts, any comments?
Mike?
Mike?
Never tried that out myself but according to MSDN MF_SYSMENU should always be in HiWOrd(wParam) as the hook's dealing with a system menu. I'd suggest to look for a value of $FFFF in HiWord(wParam) as this indicates that the menu has been closed and then use LoWord(wParam) to get the index of the last selected item (here indicated by the somewhat irritating term WM_NASTYAPP, irritating because WM_* denotes a Windows message not an identifier).
Ciao, Mike
Ciao, Mike
ASKER
Thanks Mike, I'll give it a try.
ASKER
I can't get this to work. Can anyone offer a code snippet to replace the bit that DragonSlayer left me? It's the bit in the DLL...
if (message=WM_MENUSELECT) and (LoWord(wParam)=WM_NASTYAP P) and ((HiWord(wParam) and MF_MOUSESELECT)=MF_MOUSESE LECT) then
Any ideas anyone?
John.
if (message=WM_MENUSELECT) and (LoWord(wParam)=WM_NASTYAP
Any ideas anyone?
John.
sorry about the mess there, John... :(
anyway, why do you wanna replace that code?
anyway, why do you wanna replace that code?
ASKER
Sorry about the delay....
I want to click on the menu item, but the code you gave me only detects the mouse being over it.
How do I resolve the problem?
I want to click on the menu item, but the code you gave me only detects the mouse being over it.
How do I resolve the problem?
Frankly speaking, i dunno :(
ASKER
DragonSlayer : You didn't answer the question correctly then!
Yes, but he gave it a good effort didn't he?
Rob ;-)
Rob ;-)
FYI Jaymol, I posted that as a comment, NOT an answer. It was YOU who accepted the comment as an answer.
PS: I do not intend to be rude, though.
PS: I do not intend to be rude, though.
ASKER
Yeah, I know, but I still incorrectly gave the points.
I'm sorry you see it that way then. But hey, cheer up a bit, will ya?
>Yeah, I know, but I still incorrectly gave the points.
Jaymol you know as well as I do that we live in a world that punishes us for stupid mistakes. You made a stupid mistake. :-(
Rob;-)
Jaymol you know as well as I do that we live in a world that punishes us for stupid mistakes. You made a stupid mistake. :-(
Rob;-)