unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Menus,shellapi; const wm_trayicon=wm_app+0;type TForm1 = class(TForm) PopupMenu1: TPopupMenu; N1: TMenuItem; N2: TMenuItem; procedure FormDestroy(Sender: TObject); procedure N1Click(Sender: TObject); procedure N2Click(Sender: TObject); procedure FormShow(Sender: TObject); private { Private declarations } procedure wmtrayicon(var message:tmessage); message wm_trayicon; Procedure WMSysCommand(Var msg : TMessage);Message WM_SYSCOMMAND; public { Public declarations } end;var Form1: TForm1;implementation {$R *.dfm} procedure modifytrayicon(action:dword); var nidata:tnotifyicondata; begin with nidata do begin cbsize:=sizeof(tnotifyicondata); uid:=0; uflags:=NIF_MESSAGE or NIF_ICON or NIF_TIP; wnd:=Form1.handle; ucallbackmessage:=wm_trayicon; hicon:=application.Icon.Handle ; strpcopy(sztip,application.Title ); end; shell_notifyicon(action,@nidata); end;procedure TForm1.wmtrayicon(var message:tmessage); var mousepos:tpoint; begin case message.lParam of //左键按下 WM_LBUTTONDOWN : begin application.MainForm.BringToFront; //窗体置前 end; //左键双击 WM_LBUTTONDBLCLK : begin //窗体隐含或显示 Application.MainForm.Visible := not Application.MainForm.Visible; SetForegroundWindow(Application.Handle); end; //右键按下 WM_RBUTTONDOWN : begin //显示弹出菜单 setactivewindow(handle); getcursorpos(mousepos); popupmenu1.Popup(mousepos.X,mousepos.Y); end; end//case end;procedure Tform1.WMSysCommand(var msg: TMessage); begin case Msg.WParam of SC_MINIMIZE: begin msg.WParam:=0; modifytrayicon(nim_add); Application.MainForm.Visible:=false; end; SC_CLOSE :begin msg.WParam :=0; modifytrayicon(nim_add); Application.MainForm.Visible:=false; end; end; Inherited; end;procedure TForm1.FormDestroy(Sender: TObject); begin modifytrayicon(nim_delete); //删除托盘 end;procedure TForm1.N1Click(Sender: TObject); begin Application.MainForm.Visible :=true; end;procedure TForm1.N2Click(Sender: TObject); begin close; end;procedure TForm1.FormShow(Sender: TObject); begin modifytrayicon(nim_delete); end;end.
希望对你有帮助: 在开始之前,请看下面的需要的接口方面的内容: 从技术方面来说,一个任务栏应用程序非常象普通的应用程序,它有一个消息循环,相应Windows的消息来完成相应的功能。 Procedure RunTrayApplication; Var Msg : TMsg; Begin CreateWindow; AddTrayIcon; While GetMessage(Msg,0,0,0) do Begin TranslateMessage(Msg); DispatchMessage(Msg); End; DeleteTrayIcon; End; 你能看到:所有需要做的工作是创建一个窗口,注册一个图标到任务栏,设置它的消息循环,最后关闭它。当然,必须还有增加其他代码完成相应的功能,但是,它是真的不需要担心。 让我们从窗口的创建开始。实际上,这个窗口是不是能在任务栏上能见到的窗口。相应的,这个窗口只是处理消息循环、其它父类的工作。任务窗口(Windows 95 & NT)句柄创建消息(例如鼠标单击等)和将消息发到我们的窗口。 Procedure CreateWindow; Var WC : TWndClass; W : hWnd; Begin With WC do Begin Style := 0; lpfnWndProc := @WndProc; cbClsExtra := 0; cbWndExtra := 0; hIcon := 0; hCursor := 0; hbrBackground := 0; lpszMenuName := nil; lpszClassName := 'MyTrayIconClass'; hInstance := System.hInstance; end; RegisterClass(WC); W := Windows.CreateWindow('MyTrayIconClass','MyVeryOwnTrayIconWindow', ws_OverlappedWindow,0,0,0,0,0,0,hInstance,nil); ShowWindow(W,sw_Hide); UpdateWindow(W); MainWindow := W; End; 这个窗口使用普通的窗口函数创建。注意这个窗口的类型是“ws_OverlappedWindow”,但是这个尺寸是0,并且它是隐藏的,所有,它将不会显示出来。 下一步是加(注册)我们的图标。这将需要使用Shell_NotifyIcon这个API函数,这个函数实际上可以完成三个功能,这里只需要它的增加的特性。 Procedure AddTrayIcon; Var IconData : TNotifyIconData; Begin With IconData do Begin cbSize := SizeOf(IconData); Wnd := MainWindow; uID := 0; uFlags := nif_Icon Or nif_Message Or nif_Tip; uCallBackMessage := wm_MyCallBack; hIcon := LoadIcon(hInstance,'MYICON'); StrCopy(szTip,PChar(TrayIconTip)); End; Shell_NotifyIcon(nim_Add,@IconData); End; 这个最重要的事情是TNotifyIconData的数据结构,它是一个设置Window句柄的数据结构,是一个记录参数,对我们来说,我们需要设置这个图标的窗口句柄(这将定义哪个窗口处理消息循环),回调消息号,图标,工具提示等。一旦这个数据设置了,我们就可以增加一个图标到任务栏上了。为了完成这个工作,使用nim_Add程序。 现行我们已经加了我们的图标到任务栏,下面需要决定如何处理消息。 Const wm_MyCallback = wm_User+1000; cm_Exit = 100; { we worry about... } cm_About = 101; { ...these later } 这个实际的窗口处理过程也是相当普通。几个窗口消息(如wm_NCCreate)必须处理。然而,对我们来说,更重要的事情是处理wm_MyCallback和wm_Command消息: Function WndProc(Window : hWnd; Msg,WParam,LParam : Integer): Integer; StdCall; Begin Result := 0; Case Msg of wm_NCCreate : Result := 1; wm_Destroy : PostQuitMessage(0); wm_Command : Begin { a command was chosen from the popup menu } If (WParam = cm_Exit) Then PostMessage(Window,wm_Destroy,0,0) Else If (WParam = cm_About) Then MessageBox(0,'Shell Test Copyright ?'+ 'Jani J鋜vinen 1996.', 'About Shell Test',mb_OK) Else OpenDesktopIcon(WParam-cm_About); End; wm_MyCallback : Begin { our icon was clicked } If (LParam = wm_LButtonDown) Then ShowIconPopupMenu Else If (LParam = wm_RButtonDown) Then ShowAboutPopupMenu; End; Else Result := DefWindowProc(Window,Msg,WParam,LParam); End; End; 就象你看到的一样,当用户单击图标时,Windows提示我们。注意我们不使用通常使用的wm_LButtonDown 消息,而使用wm_MyCallback message,详细的消息信息存储在LParam参数中。 当用户单击鼠标右键,我们创建一个菜单在桌面上。 Type TIconData = Array[1..100] of String; Var IconData : TIconData; Procedure ShowIconPopupMenu; Var ShellFolder : IShellFolder; EnumIDList : IEnumIDList; Result : hResult; Dummy : ULong; ItemIDList : TItemIDList; Pntr : PItemIDList; StrRet : TStrRet; PopupMenu : hMenu; ItemID : Integer; Pos : TPoint; Procedure AddToMenu(Item : String); Var S : String; Begin IconData[ItemID-cm_About] := Item; S := ExtractFileName(Item); If (System.Pos('.',S) <> 0) Then SetLength(S,System.Pos('.',S)-1); AppendMenu(PopupMenu,mf_Enabled Or mf_String,ItemID,PChar(S)); Inc(ItemID); End; begin PopupMenu := CreatePopupMenu; ItemID := cm_About+1; SHGetDesktopFolder(ShellFolder); ShellFolder.EnumObjects(MainWindow,SHCONTF_NONFOLDERS,EnumIDList); Pntr := @ItemIDList; Result := EnumIDList.Next(1,Pntr,Dummy); While (Result = NoError) do Begin ShellFolder.GetDisplayNameOf(Pntr,SHGDN_FORPARSING,@StrRet); With StrRet do AddToMenu(String(CStr)); Result := EnumIDList.Next(1,Pntr,Dummy); End; EnumIDList.Release; ShellFolder.Release; GetCursorPos(Pos); AppendMenu(PopupMenu,mf_Separator,0,''); AppendMenu(PopupMenu,mf_Enabled Or mf_String,cm_Exit,'E&xit'); SetForegroundWindow(MainWindow); TrackPopupMenu(PopupMenu,tpm_LeftAlign Or tpm_LeftButton, Pos.X,Pos.Y,0,MainWindow,nil); DestroyMenu(PopupMenu); end; 上面的程序看起来有点复杂,你可以将它分成两个部分来看:创建和显示菜单。 列举创建菜单是用Windows的外壳接口完成的。首先,我们使用SHGetDesktopForlder函数得到使用桌面的IShellFolder接口。使用这个接口,我们能得到另一个接口的实例:IEnumIDList。这个接口通常实现实际的列举工作。我们简单的重复调用这个函数直到错误值返回(例如:所有的菜单被列举)。当我们得到一个菜单,我们使用AddToMenu函数加它。 当所有的菜单被列举和创建后,现在我们需要运行这个菜单。我们将找到的菜单保存到一个全局的List变量中,每一个菜单都拥有它的菜单号。这确保我们能得到它的索引。
OpenDesktopIcon(WParam-cm_About) 当然,WParam中储存了用户单击鼠标的菜单的菜单号(ID)。 下面我们将处理运行用户选择的菜单。 Procedure OpenDesktopIcon(Number : Integer); Var S : String; I : Integer; begin S := IconData[Number]; I := ShellExecute(0,nil,PChar(S),nil,nil,sw_ShowNormal); If (I < 32) Then Begin S := 'Could not open selected item "'+S+'". '+ 'Result was: '+IntToStr(I)+'.'; MessageBox(0,PChar(S),'Shell Test',mb_OK); End; end; 上面,Win 32 API函数ShellExecute做了所有的工作。
搜索一下吧,以前的很多
http://expert.csdn.net/Expert/topic/1853/1853515.xml?temp=.6273462
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Menus,shellapi;
const
wm_trayicon=wm_app+0;type
TForm1 = class(TForm)
PopupMenu1: TPopupMenu;
N1: TMenuItem;
N2: TMenuItem;
procedure FormDestroy(Sender: TObject);
procedure N1Click(Sender: TObject);
procedure N2Click(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
procedure wmtrayicon(var message:tmessage); message wm_trayicon;
Procedure WMSysCommand(Var msg : TMessage);Message WM_SYSCOMMAND;
public
{ Public declarations }
end;var
Form1: TForm1;implementation
{$R *.dfm}
procedure modifytrayicon(action:dword);
var
nidata:tnotifyicondata;
begin
with nidata do begin
cbsize:=sizeof(tnotifyicondata);
uid:=0;
uflags:=NIF_MESSAGE or NIF_ICON or NIF_TIP;
wnd:=Form1.handle;
ucallbackmessage:=wm_trayicon;
hicon:=application.Icon.Handle ;
strpcopy(sztip,application.Title );
end;
shell_notifyicon(action,@nidata);
end;procedure TForm1.wmtrayicon(var message:tmessage);
var
mousepos:tpoint;
begin
case message.lParam of
//左键按下
WM_LBUTTONDOWN : begin
application.MainForm.BringToFront; //窗体置前
end;
//左键双击
WM_LBUTTONDBLCLK : begin //窗体隐含或显示
Application.MainForm.Visible := not Application.MainForm.Visible;
SetForegroundWindow(Application.Handle);
end;
//右键按下
WM_RBUTTONDOWN : begin //显示弹出菜单
setactivewindow(handle);
getcursorpos(mousepos);
popupmenu1.Popup(mousepos.X,mousepos.Y);
end;
end//case
end;procedure Tform1.WMSysCommand(var msg: TMessage);
begin
case Msg.WParam of
SC_MINIMIZE: begin
msg.WParam:=0;
modifytrayicon(nim_add);
Application.MainForm.Visible:=false;
end;
SC_CLOSE :begin
msg.WParam :=0;
modifytrayicon(nim_add);
Application.MainForm.Visible:=false;
end;
end;
Inherited;
end;procedure TForm1.FormDestroy(Sender: TObject);
begin
modifytrayicon(nim_delete); //删除托盘
end;procedure TForm1.N1Click(Sender: TObject);
begin
Application.MainForm.Visible :=true;
end;procedure TForm1.N2Click(Sender: TObject);
begin
close;
end;procedure TForm1.FormShow(Sender: TObject);
begin
modifytrayicon(nim_delete);
end;end.
Var Msg : TMsg;
Begin
CreateWindow;
AddTrayIcon;
While GetMessage(Msg,0,0,0) do Begin
TranslateMessage(Msg);
DispatchMessage(Msg);
End;
DeleteTrayIcon;
End;
你能看到:所有需要做的工作是创建一个窗口,注册一个图标到任务栏,设置它的消息循环,最后关闭它。当然,必须还有增加其他代码完成相应的功能,但是,它是真的不需要担心。
让我们从窗口的创建开始。实际上,这个窗口是不是能在任务栏上能见到的窗口。相应的,这个窗口只是处理消息循环、其它父类的工作。任务窗口(Windows 95 & NT)句柄创建消息(例如鼠标单击等)和将消息发到我们的窗口。 Procedure CreateWindow;
Var
WC : TWndClass;
W : hWnd;
Begin
With WC do Begin
Style := 0;
lpfnWndProc := @WndProc;
cbClsExtra := 0;
cbWndExtra := 0;
hIcon := 0;
hCursor := 0;
hbrBackground := 0;
lpszMenuName := nil;
lpszClassName := 'MyTrayIconClass';
hInstance := System.hInstance;
end;
RegisterClass(WC);
W := Windows.CreateWindow('MyTrayIconClass','MyVeryOwnTrayIconWindow',
ws_OverlappedWindow,0,0,0,0,0,0,hInstance,nil);
ShowWindow(W,sw_Hide);
UpdateWindow(W);
MainWindow := W;
End;
这个窗口使用普通的窗口函数创建。注意这个窗口的类型是“ws_OverlappedWindow”,但是这个尺寸是0,并且它是隐藏的,所有,它将不会显示出来。
下一步是加(注册)我们的图标。这将需要使用Shell_NotifyIcon这个API函数,这个函数实际上可以完成三个功能,这里只需要它的增加的特性。 Procedure AddTrayIcon;
Var IconData : TNotifyIconData;
Begin
With IconData do Begin
cbSize := SizeOf(IconData);
Wnd := MainWindow;
uID := 0;
uFlags := nif_Icon Or nif_Message Or nif_Tip;
uCallBackMessage := wm_MyCallBack;
hIcon := LoadIcon(hInstance,'MYICON');
StrCopy(szTip,PChar(TrayIconTip));
End;
Shell_NotifyIcon(nim_Add,@IconData);
End;
这个最重要的事情是TNotifyIconData的数据结构,它是一个设置Window句柄的数据结构,是一个记录参数,对我们来说,我们需要设置这个图标的窗口句柄(这将定义哪个窗口处理消息循环),回调消息号,图标,工具提示等。一旦这个数据设置了,我们就可以增加一个图标到任务栏上了。为了完成这个工作,使用nim_Add程序。
现行我们已经加了我们的图标到任务栏,下面需要决定如何处理消息。 Const
wm_MyCallback = wm_User+1000;
cm_Exit = 100; { we worry about... }
cm_About = 101; { ...these later }
这个实际的窗口处理过程也是相当普通。几个窗口消息(如wm_NCCreate)必须处理。然而,对我们来说,更重要的事情是处理wm_MyCallback和wm_Command消息:
Function WndProc(Window : hWnd; Msg,WParam,LParam : Integer): Integer; StdCall;
Begin
Result := 0;
Case Msg of
wm_NCCreate : Result := 1;
wm_Destroy : PostQuitMessage(0);
wm_Command : Begin { a command was chosen from the popup menu }
If (WParam = cm_Exit) Then
PostMessage(Window,wm_Destroy,0,0)
Else If (WParam = cm_About) Then
MessageBox(0,'Shell Test Copyright ?'+
'Jani J鋜vinen 1996.',
'About Shell Test',mb_OK)
Else OpenDesktopIcon(WParam-cm_About);
End;
wm_MyCallback : Begin { our icon was clicked }
If (LParam = wm_LButtonDown) Then
ShowIconPopupMenu
Else If (LParam = wm_RButtonDown) Then
ShowAboutPopupMenu;
End;
Else Result := DefWindowProc(Window,Msg,WParam,LParam);
End;
End;
就象你看到的一样,当用户单击图标时,Windows提示我们。注意我们不使用通常使用的wm_LButtonDown 消息,而使用wm_MyCallback message,详细的消息信息存储在LParam参数中。
当用户单击鼠标右键,我们创建一个菜单在桌面上。 Type
TIconData = Array[1..100] of String;
Var
IconData : TIconData;
Procedure ShowIconPopupMenu;
Var
ShellFolder : IShellFolder;
EnumIDList : IEnumIDList;
Result : hResult;
Dummy : ULong;
ItemIDList : TItemIDList;
Pntr : PItemIDList;
StrRet : TStrRet;
PopupMenu : hMenu;
ItemID : Integer;
Pos : TPoint;
Procedure AddToMenu(Item : String);
Var S : String;
Begin
IconData[ItemID-cm_About] := Item;
S := ExtractFileName(Item);
If (System.Pos('.',S) <> 0) Then SetLength(S,System.Pos('.',S)-1);
AppendMenu(PopupMenu,mf_Enabled Or mf_String,ItemID,PChar(S));
Inc(ItemID);
End;
begin
PopupMenu := CreatePopupMenu;
ItemID := cm_About+1;
SHGetDesktopFolder(ShellFolder);
ShellFolder.EnumObjects(MainWindow,SHCONTF_NONFOLDERS,EnumIDList);
Pntr := @ItemIDList;
Result := EnumIDList.Next(1,Pntr,Dummy);
While (Result = NoError) do Begin
ShellFolder.GetDisplayNameOf(Pntr,SHGDN_FORPARSING,@StrRet);
With StrRet do AddToMenu(String(CStr));
Result := EnumIDList.Next(1,Pntr,Dummy);
End;
EnumIDList.Release;
ShellFolder.Release;
GetCursorPos(Pos);
AppendMenu(PopupMenu,mf_Separator,0,'');
AppendMenu(PopupMenu,mf_Enabled Or mf_String,cm_Exit,'E&xit');
SetForegroundWindow(MainWindow);
TrackPopupMenu(PopupMenu,tpm_LeftAlign Or tpm_LeftButton,
Pos.X,Pos.Y,0,MainWindow,nil);
DestroyMenu(PopupMenu);
end;
上面的程序看起来有点复杂,你可以将它分成两个部分来看:创建和显示菜单。
列举创建菜单是用Windows的外壳接口完成的。首先,我们使用SHGetDesktopForlder函数得到使用桌面的IShellFolder接口。使用这个接口,我们能得到另一个接口的实例:IEnumIDList。这个接口通常实现实际的列举工作。我们简单的重复调用这个函数直到错误值返回(例如:所有的菜单被列举)。当我们得到一个菜单,我们使用AddToMenu函数加它。 当所有的菜单被列举和创建后,现在我们需要运行这个菜单。我们将找到的菜单保存到一个全局的List变量中,每一个菜单都拥有它的菜单号。这确保我们能得到它的索引。
OpenDesktopIcon(WParam-cm_About) 当然,WParam中储存了用户单击鼠标的菜单的菜单号(ID)。 下面我们将处理运行用户选择的菜单。 Procedure OpenDesktopIcon(Number : Integer);
Var
S : String;
I : Integer;
begin
S := IconData[Number];
I := ShellExecute(0,nil,PChar(S),nil,nil,sw_ShowNormal);
If (I < 32) Then Begin
S := 'Could not open selected item "'+S+'". '+
'Result was: '+IntToStr(I)+'.';
MessageBox(0,PChar(S),'Shell Test',mb_OK);
End;
end;
上面,Win 32 API函数ShellExecute做了所有的工作。