When you run your application a button appears on the Windows Taskbar. Users can left-click the taskbar button to activate the application. When a user right-clicks the taskbar button a system menu gets displayed for the application.
By design, Delphi applications display only three items in the system menu: Restore, Minimize and Close. "Standard" Windows applications show three more: Maximize, Size and Move.
You can alter the system menu programmatically. The code is not trivial, requires a lot of knowledge of the Windows API, and finally you do not work with the standard TMenuItem as you are used to in Delphi.
To be able to fully customize the menu that appears when the Taskbar button is clicked and still operate on the TMenuItem objects you might need a custom menu component...
The undocumented 0x0313 Windows Message
When you right-click on a taskbar button, Windows sends an undocumented message ($0313) to the corresponding application window. The WPARAM is unused (zero) and the LPARAM contains the mouse position in screen coordinates, in the usual format. By default, WindowProc handles this message by popping up the system menu at the given coordinates.TTaskBarMenu - custom Delphi TaskBar Menu component
To show a custom menu when the application receives the undocumented 0x0313 Windows message a custom TTaskBarMenu component needs to override the WindowProc method that handles all the messages passed to the application by Windows. Hint: handling Windows messages in DelphiThe TTaskBarMenu extends the standard TPopupMenu Delphi component by handling the secret $0313 message.
~~~~~~~~~~~~~~~~~~~~~~~~~
unit TaskBarMenu;
interface
uses
SysUtils, Classes, Menus, Messages, Windows, Forms, Controls;
type
TTaskBarMenu = class(TPopupMenu)
private
hookHandle : THandle;
oldWndProc: Pointer;
newWndProc: Pointer;
protected
procedure Hook;
procedure UnHook;
procedure AppWndProc(var Msg: TMessage) ;
public
constructor Create(AOwner: TComponent) ; override;
destructor Destroy; override;
end;
procedure Register;
implementation
const
WM_TASKBAR_MENU = $0313; // magic!
WM_POPUP_MENU = WM_USER + 1; //custom message
var
thisOnce : TTaskBarMenu = nil;
procedure Register;
begin
RegisterComponents('delphi.about.com', [TTaskBarMenu]) ;
end;
{ TTaskBarMenu }
procedure TTaskBarMenu.AppWndProc(var Msg: TMessage) ;
begin
case Msg.Msg of
WM_TASKBAR_MENU: PostMessage(hookHandle, WM_POPUP_MENU, 0, 0) ;
WM_POPUP_MENU: Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y) ;
else
Msg.Result := CallWindowProc(oldWndProc, hookHandle, Msg.Msg, Msg.wParam, Msg.lParam) ;
end;
end; (*AppWndProc*)
constructor TTaskBarMenu.Create(AOwner: TComponent) ;
begin
if Assigned(thisOnce) then
begin
raise Exception.Create('Only one instance of this component can be used per application!') ;
end
else
begin
inherited;
thisOnce := self;
hookHandle := Application.Handle;
Hook;
end;
end; (*Create*)
destructor TTaskBarMenu.Destroy;
begin
thisOnce := nil;
UnHook;
inherited;
end; (*Destroy*)
procedure TTaskBarMenu.Hook;
begin
oldWndProc := Pointer(GetWindowLong(hookHandle, GWL_WNDPROC)) ;
newWndProc := Classes.MakeObjectInstance(AppWndProc) ;
if not (csDesigning in ComponentState) then SetWindowLong(hookHandle, GWL_WNDPROC, longint(newWndProc)) ;
end; (*Hook*)
procedure TTaskBarMenu.UnHook;
begin
SetWindowLong(hookHandle, GWL_WNDPROC, longint(oldWndProc)) ;
if Assigned(newWndProc) then Classes.FreeObjectInstance(newWndProc) ;
NewWndProc := nil;
end; (*UnHook*)
end.
~~~~~~~~~~~~~~~~~~~~~~~~~
TTaskBarMenu Test Delphi Application
No need for this! Simply drop the TTaskBarMenu on your main form, add some menu items, add programming logic and run the application!Ah, ok! Here's a demo application that uses owner drawing to display a nice looking taskbar menu.


