从技术方面来说,一个任务栏应用程序非常象普通的应用程序,它有一个消息循环,相应windows的消息来完成相应的功能。 <br><br>procedure runtrayapplication;<br>var msg : tmsg;<br>begin<br> createwindow;<br> addtrayicon;<br> while getmessage(msg,0,0,0) do begin<br> translatemessage(msg);<br> dispatchmessage(msg);<br> end;<br> deletetrayicon;<br>end;<br> 你能看到:所有需要做的工作是创建一个窗口,注册一个图标到任务栏,设置它的消息循环,最后关闭它。当然,必须还有增加其他代码完成相应的功能,但是,它是真的不需要担心。 <br><br> 让我们从窗口的创建开始。实际上,这个窗口是不是能在任务栏上能见到的窗口。相应的,这个窗口只是处理消息循环、其它父类的工作。任务窗口(windows 95 & nt)句柄创建消息(例如鼠标单击等)和将消息发到我们的窗口。 <br><br>procedure createwindow;<br>var<br> wc : twndclass;<br> w : hwnd;<br>begin<br> with wc do begin<br> style := 0;<br> lpfnwndproc := @wndproc;<br> cbclsextra := 0;<br> cbwndextra := 0;<br> hicon := 0;<br> hcursor := 0;<br> hbrbackground :=di2001.jpg;<br> lpszmenuname := nil;<br> lpszclassname := 'mytrayiconclass';<br> hinstance := system.hinstance;<br> end;<br> registerclass(wc);<br> w := windows.createwindow('mytrayiconclass', 'myveryowntrayiconwindow',<br> ws_overlappedwindow, 0, 0, 0, 0, 0, 0, hinstance, nil);<br> showwindow(w,sw_hide);<br> updatewindow(w);<br> mainwindow := w;<br>end;<br> <br><br> 这个窗口使用普通的窗口函数创建。注意这个窗口的类型是“ws_overlappedwindow”,但是这个尺寸是0,并且它是隐藏的,所有,它将不会显示出来。 <br><br> 下一步是加(注册)我们的图标。这将需要使用shell_notifyicon这个api函数,这个函数实际上可以完成三个功能,这里只需要它的增加的特性。 <br><br>procedure addtrayicon;<br>var icondata : tnotifyicondata;<br>begin<br> with icondata do begin<br> cbsize := sizeof(icondata);<br> wnd := mainwindow;<br> uid := 0;<br> uflags := nif_icon or nif_message or nif_tip;<br> ucallbackmessage := wm_mycallback;<br> hicon := loadicon(hinstance,'myicon');<br> strcopy(sztip,pchar(trayicontip));<br> end;<br> shell_notifyicon(nim_add,@icondata);<br>end;<br> <br><br> 这个最重要的事情是tnotifyicondata的数据结构,它是一个设置window句柄的数据结构,是一个记录参数,对我们来说,我们需要设置这个图标的窗口句柄(这将定义哪个窗口处理消息循环),回调消息号,图标,工具提示等。一旦这个数据设置了,我们就可以增加一个图标到任务栏上了。为了完成这个工作,使用nim_add程序。 <br><br> 现行我们已经加了我们的图标到任务栏,下面需要决定如何处理消息。 <br><br>const<br> wm_mycallback = wm_user+1000;<br> cm_exit = 100; { we worry about... }<br> cm_about = 101; { ...these later }<br> <br><br> 这个实际的窗口处理过程也是相当普通。几个窗口消息(如wm_nccreate)必须处理。然而,对我们来说,更重要的事情是处理wm_mycallback和wm_command消息: <br><br>function wndproc (window : hwnd; msg, wparam, lparam : integer): integer; stdcall;<br>begin<br> result := 0;<br> case msg of<br> wm_nccreate : result := 1;<br> wm_destroy : postquitmessage(0);<br> wm_command : begin { a command was chosen from the popup menu }<br> if (wparam = cm_exit) then<br> postmessage(window,wm_destroy,0,0)<br> else if (wparam = cm_about) then<br> messagebox(0,'shell test copyright ?'+<br> 'jani j鋜vinen 1996.',<br> 'about shell test',mb_ok)<br> else opendesktopicon(wparam-cm_about);<br> end;<br> wm_mycallback : begin { our icon was clicked }<br> if (lparam = wm_lbuttondown) then<br> showiconpopupmenu<br> else if (lparam = wm_rbuttondown) then<br> showaboutpopupmenu;<br> end;<br> else result := defwindowproc(window,msg,wparam,lparam);<br> end;<br>end;<br> <br><br> 就象你看到的一样,当用户单击图标时,windows提示我们。注意我们不使用通常使用的wm_lbuttondown 消息,而使用wm_mycallback message,详细的消息信息存储在lparam参数中。 <br><br> 当用户单击鼠标右键,我们创建一个菜单在桌面上。 <br><br>type<br> ticondata = array[1..100] of string;<br>var<br> icondata : ticondata;<br>procedure showiconpopupmenu;<br>var<br> shellfolder : ishellfolder;<br> enumidlist : ienumidlist;<br> result : hresult;<br> dummy : ulong;<br> itemidlist : titemidlist;<br> pntr : pitemidlist;<br> strret : tstrret;<br> popupmenu : hmenu;<br> itemid : integer;<br> pos : tpoint;<br> procedure addtomenu(item : string);<br> var s : string;<br> begin<br> icondata[itemid-cm_about] := item;<br> s := extractfilename(item);<br> if (system.pos('.',s) <> 0) then setlength(s,system.pos('.',s)-1);<br> appendmenu(popupmenu,mf_enabled or mf_string,itemid,pchar(s));<br> inc(itemid);<br> end;<br>begin<br> popupmenu := createpopupmenu;<br> itemid := cm_about+1;<br> shgetdesktopfolder(shellfolder);<br> shellfolder.enumobjects(mainwindow,shcontf_nonfolders,enumidlist);<br> pntr := @itemidlist;<br> result := enumidlist.next(1,pntr,dummy);<br> while (result = noerror) do begin<br> shellfolder.getdisplaynameof(pntr,shgdn_forparsing,@strret);<br> with strret do addtomenu(string(cstr));<br> result := enumidlist.next(1,pntr,dummy);<br> end;<br> enumidlist.release;<br> shellfolder.release;<br> getcursorpos(pos);<br> appendmenu(popupmenu,mf_separator,0,'');<br> appendmenu(popupmenu,mf_enabled or mf_string,cm_exit,'e&xit');<br> setforegroundwindow(mainwindow);<br> trackpopupmenu(popupmenu,tpm_leftalign or tpm_leftbutton,<br> pos.x,pos.y,0,mainwindow,nil);<br> destroymenu(popupmenu);<br>end;<br> <br><br> 上面的程序看起来有点复杂,你可以将它分成两个部分来看:创建和显示菜单。 <br><br> 列举创建菜单是用windows的外壳接口完成的。首先,我们使用shgetdesktopforlder函数得到使用桌面的ishellfolder接口。使用这个接口,我们能得到另一个接口的实例:ienumidlist。这个接口通常实现实际的列举工作。我们简单的重复调用这个函数直到错误值返回(例如:所有的菜单被列举)。当我们得到一个菜单,我们使用addtomenu函数加它。 <br><br> 当所有的菜单被列举和创建后,现在我们需要运行这个菜单。我们将找到的菜单保存到一个全局的list变量中,每一个菜单都拥有它的菜单号。这确保我们能得到它的索引。 <br><br> opendesktopicon(wparam-cm_about) <br><br>当然,wparam中储存了用户单击鼠标的菜单的菜单号(id)。 <br><br> 下面我们将处理运行用户选择的菜单。 <br><br>procedure opendesktopicon(number : integer);<br>var<br> s : string;<br> i : integer;<br>begin<br> s := icondata[number];<br> i := shellexecute(0,nil,pchar(s),nil,nil,sw_shownormal);<br> if (i < 32) then begin<br> s := 'could not open selected item "'+s+'". '+<br> 'result was: '+inttostr(i)+'.';<br> messagebox(0,pchar(s),'shell test',mb_ok);<br> end;<br>end;<br> <br><br> 上面,win 32 api函数shellexecute做了所有的工作。 <br><br> 现在你应该能用delphi创建简单的任务栏的程序了。 <br>