1. Technology

TTaskBarMenu - Windows TaskBar Custom Menu Component

By

TTaskBarMenu - Windows TaskBar Custom Menu Component

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 Delphi

The 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.

Installing into the Component palette

First, download the TTaskBarMenu component. The TMemoBar comes as a single unit file (.pas extension). You'll need to add the component into an existing package. Here's How to Install Custom Component in Delphi (into Existing Package).
Related Video
Using PHP With HTML

©2014 About.com. All rights reserved.