Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Another App's System Menu.

Posted on 1999-10-25
35
Medium Priority
?
276 Views
Last Modified: 2010-04-04
I have added a new menu item to another application.  I now need to know how to handle it.  Any suggestions?
0
Comment
Question by:Jaymol
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 15
  • 7
  • 3
  • +5
35 Comments
 
LVL 4

Expert Comment

by:Radler
ID: 2155674
How this was done ?
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2155694
Simple....

assume you have the handle of a running application and use the following code...(Hndl=handle)

var
  SysMenu : HMenu;
begin
  SysMenu:=GetSystemMenu(Hndl, 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.
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2155932
Okay then...more points.  (But no more.)
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 7

Expert Comment

by:RBertora
ID: 2156044
following..
0
 
LVL 4

Expert Comment

by:Radler
ID: 2156064
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.
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2156072
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.
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 2156074
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
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2156085
That's what I'm asking
0
 
LVL 4

Expert Comment

by:BoRiS
ID: 2156106
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(Sender: 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
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2156143
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
0
 
LVL 4

Expert Comment

by:Radler
ID: 2156150
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.
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2156186
Boris, isn't that only gonna work for MY application?
0
 
LVL 4

Expert Comment

by:BoRiS
ID: 2156196
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...
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2156208
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. :-(
0
 
LVL 10

Expert Comment

by:viktornet
ID: 2156435
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=-..
0
 
LVL 14

Accepted Solution

by:
DragonSlayer earned 280 total points
ID: 2156473
Here's something I wrote some time ago:

library NastyHook;

uses
  SysUtils, Windows, Messages,
  Classes;

const WM_NASTYAPP=WM_USER+101;

var HookHandle: hHook=0;
    MsgStruct: PCWPStruct;
    HookSet: Boolean=False;

function GetMsgProc(nCode: integer; wParam: WPARAM; lParam: LPARAM): longint; stdcall;
begin
     Result:=0;
     MsgStruct:=Pointer(lParam);
     if (nCode=HC_ACTION) THEN
     begin
          with MsgStruct^ do
          begin
               if (message=WM_MENUSELECT) and
                  (LoWord(wParam)=WM_NASTYAPP) and
                  ((HiWord(wParam) and MF_MOUSESELECT)=MF_MOUSESELECT) then
               begin
                    MessageBox(hWnd, 'Hello, Thanx for trying Nasty App!',
                               'Nasty App', MB_OK or MB_TASKMODAL or MB_ICONINFORMATION);
               end else
                   Result:=CallNextHookEx(HookHandle, nCode, wParam, lParam);
          end;
     end else
         Result:=CallNextHookEx(HookHandle, nCode, wParam, lParam);
end;

function SetHook: boolean;
begin
     Result:=False;
     if HookSet then exit;
     HookHandle:=SetWindowsHookEx(WH_CALLWNDPROC, GetMsgProc, hInstance, 0);
     Result:=HookHandle<>0;
     HookSet:=True;
end;

function ReleaseHook: boolean;
begin
     Result:=False;
     if not(HookSet) then
        exit;
     Result:=UnHookWindowsHookEx(HookHandle);
     HookSet:=not Result;
end;

exports SetHook,
        ReleaseHook;

begin
end.


And then my application will have something like this:

function SetHook: Boolean; external 'NASTYHOOK.DLL' name 'SetHook';
function ReleaseHook: Boolean; external 'NASTYHOOK.DLL' name 'ReleaseHook';

function EnumWindowsProc(Hw: hWnd; TF: TfrmMain): Boolean; stdCall;
var TheMenu: HMENU;
{ Minimize=61472, Close=65536, Maximize=61488,
  Restore=61728,  Move=61456, Size=61440       }
begin
     Result:=True;
     { some don't have system menus }
     TheMenu:=GetSystemMenu(Hw, False);
     { let's not modify ourself }
     if Hw=frmMain.Handle then
        exit;

     AppendMenu(TheMenu, MF_SEPARATOR, 101, nil);
     AppendMenu(TheMenu, MF_STRING, WM_NASTYAPP, '&Nasty App Forever...');
     { make as default, usable in Win95/98 only }
     SetMenuDefaultItem(TheMenu, WM_NASTYAPP, 0);
     DrawMenuBar(Hw);
end;


That's all.  But something might be wrong with my code... it runs perfectly well under WinNT but crashes sometimes under W95/98.

Enjoy!


DragonSlayer
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2158098
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
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2158149
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.
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2158162
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.
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2158508
Will somebody PLEASE give me a clue?
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 2159743
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
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2161795
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.
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 2163491
Experts, any comments?
Mike?
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2164915
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
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2164951
Thanks Mike, I'll give it a try.
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2164980
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_NASTYAPP) and ((HiWord(wParam) and MF_MOUSESELECT)=MF_MOUSESELECT) then


Any ideas anyone?

John.
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 2165031
sorry about the mess there, John... :(

anyway, why do you wanna  replace that code?
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2193687
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?
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 2196058
Frankly speaking, i dunno :(
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2196520
DragonSlayer : You didn't answer the question correctly then!
0
 
LVL 7

Expert Comment

by:RBertora
ID: 2196557
Yes, but he gave it a good effort didn't he?
Rob ;-)
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 2196811
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.
0
 
LVL 6

Author Comment

by:Jaymol
ID: 2197366
Yeah, I know, but I still incorrectly gave the points.
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 2198929
I'm sorry you see it that way then.  But hey, cheer up a bit, will ya?
0
 
LVL 7

Expert Comment

by:RBertora
ID: 2199652
>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;-)
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Suggested Courses

660 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question