系统托盘问题。<br>还是自己做吧,这样既保险,又灵活。<br>网上有很多这方面的例子。<br>无非是调用几个 windows API<br>MSDN中也有例子。<br><br>核心代码都在下面的程序中。<br><br>一个功能很强的程序<br>本程序象C语言一样,用Delphi也能写出只有几十K、十几K、甚至只有几K的小程序,本文以一个能将Win95桌面藏起来的小程序为例,还涉及 TrayIcon的显示。<br>本程序能写得很小的诀窍是:根本没有用任何的 Form 。也就是说,源程序只有一个Prog1.dpr 文件,当然资源文件是不能少的。资源中包括桌面两种状态的图标。程序完全用标准的 WINAPI 写成,由于用到的资源很少,所以程序的体积也很小。当然,用这样的方法编程时不能使用 Delphi的所见即所得的编程方式。<br>本程序用到了如下一些功能:<br><br>在任务栏上显示图标,不同状态的切换 <br>只用一个工程文件,运行中注册建立窗口 <br>点击任务栏显隐桌面<br>ShowWindow(FindWindow('Progman',nil),SW_RESTORE|SW_HIDE); <br>运行中建立弹出菜单,对菜单命令的处理 <br>不显示程序窗口,程序不能重复运行 <br>注册窗口对不同消息的控制 <br>program prog1;<br>{prog1.dpr}<br>uses Windows, Messages, ShellAPI, sysutils;<br>{$R *.RES}<br>{可以看出本程序比普通的 Delphi 程序用到的 Unit 少的多。 下面声明了全局常量和变量,暂时可以不管他们。}<br>const<br> AppName = 'DeskTop Hide';<br>var<br> x: integer;<br> tid: TNotifyIconData;<br> WndClass: array[0..50] of char;<br><br>procedure HandleCommand (Wnd: hWnd; Cmd: Word);<br>begin<br> case Cmd of<br> Ord ('A'): MessageBox (0, 'Freeware brian.slack@strath.ac.uk 1997',AppName, mb_ok);<br> Ord ('E'): PostMessage (Wnd, wm_Close, 0, 0);<br> end;<br>end;<br><br><br>function DummyWindowProc (Wnd: hWnd; Msg, wParam: Word; lParam: LongInt):LongInt; stdcall;<br>{注意这里有一个 stdcall;定义了回调函数}<br>var<br> TrayHandle: Thandle;<br> dc: hDC;<br> pm: Hmenu;<br> pt: Tpoint;<br>begin<br> DummyWindowProc := 0;<br> {下面两句是找到 Win95 任务栏的句柄}<br> StrPCopy(@WndClass[0], 'Progman');<br> TrayHandle := FindWindow(@WndClass[0], nil);<br> {下面开始处理消息}<br> case Msg of<br> {收到窗口创建消息 - 在任务栏上显示一个图标}<br> wm_Create: // Program initialisation - just set up a tray icon<br> begin<br> tid.cbSize := sizeof (tid);<br> tid.Wnd := Wnd;<br> tid.uID := 1;<br> tid.uFlags := nif_Message or nif_Icon or nif_Tip;<br> tid.uCallBackMessage := wm_User;<br> tid.hIcon := LoadIcon (hInstance, 'mainICON');<br> lstrcpy (tid.szTip,'Desktop is on');<br> Shell_NotifyIcon (nim_Add, @tid);<br> end;<br> wm_Destroy: {收到关闭窗口消息时的处理}<br> begin<br> Shell_NotifyIcon (nim_Delete, @tid);<br> PostQuitMessage (0);<br> ShowWindow(TrayHandle, SW_RESTORE);<br> end;<br><br> {收到菜单消息时调用 HandleCommand 过程,并退出函数}<br> wm_Command: // Command notification<br> begin<br> HandleCommand (Wnd, LoWord (wParam));<br> Exit;<br> end;<br><br> {收到其他用户消息时的处理}<br> wm_User: // Had a tray notification - see what to do<br> {如果单击了鼠标左键, 则打开或关闭桌面}<br> if (lParam = wm_LButtonDown) then<br> begin<br> if x = 0 then<br> begin<br> ShowWindow(TrayHandle, SW_HIDE);<br> tid.hIcon := LoadIcon (hInstance, 'OFFICON');<br> lstrcpy (tid.szTip,'Desktop is off');<br> Shell_NotifyIcon (NIM_MODIFY, @tid);<br> x:=1<br> end else<br> begin<br> ShowWindow(TrayHandle, SW_RESTORE);<br> tid.hIcon := LoadIcon (hInstance, 'ONICON');<br> lstrcpy (tid.szTip,'Desktop is on');<br> Shell_NotifyIcon (NIM_MODIFY, @tid);<br> x:= 0;<br> end; {end of if}<br> end else<br> {如果是鼠标右键,则动态生成一个弹出式菜单}<br> if (lParam = wm_RButtonDown) then<br> begin<br> GetCursorPos (pt);<br> pm := CreatePopupMenu;<br> AppendMenu (pm, 0, Ord ('A'), 'About DeskTop Hide...');<br> AppendMenu (pm, mf_Separator, 0, Nil);<br> AppendMenu (pm, 0, Ord ('E'), 'Exit DeskTop Hide');<br> SetForegroundWindow (Wnd);<br> dc := GetDC (0);<br> if TrackPopupMenu (pm, tpm_BottomAlign or tpm_RightAlign,<br> pt.x,pt.y, 0, Wnd, Nil)<br> then SetForegroundWindow (Wnd);<br> DestroyMenu (pm)<br> end; {end of if}<br> end; {end of case}<br> {在处理过消息之后,还要调用默认函数,<br>以完成标准的Windows程序应该执行的任务,<br>所以这一句非常重要}<br> DummyWindowProc := DefWindowProc (Wnd, Msg, wParam, lParam);<br>end;<br>{这个就是处理菜单消息的过程}<br>{现在看来,程序的主框架很明了,但是它还不能完成任何任务。<br>过程 Panic将显示一个对话框后退出程序,<br>它在 Winmain 过程的开始部分被调用,<br>其实 Panic的功能很简单,之所以要写成一个函数的原因<br>恐怕一方面是结构化编程的需要,<br>另一方面借此避开了 String 和 Pchar 的转换。}<br>procedure Panic (szMessage: Pchar);<br>begin<br> if szMessage <> Nil then<br> MessageBox (0, szMessage, AppName, mb_ok);<br> Halt (0);<br>end;<br><br><br>{现在进入程序的主要部分,首先是定义了一批过程,<br>为了能让读者更好地理解,我们先把这些过程跳过去,<br>先说主程序。主程序位于程序的最后,<br>这样做的好处是可以直接使用程序中定义的过程。<br>主程序十分简单:}<br>procedure WinMain;<br>var<br> Wnd: hWnd; {声明窗口句柄(Handle)变量}<br> Msg: TMsg; {声明消息变量}<br> cls: TWndClass; {窗口类变量}<br>begin<br> { Previous instance running ? If so, exit }<br> { 检查是否程序已经运行,如果已经运行则调用Panic过程退出 }<br> if FindWindow (AppName, Nil) <> 0 then<br> Panic (AppName + ' is already running.');<br> { Register the window class }<br> { 这里的注册窗口类程序是例行公事,照抄即可}<br> FillChar (cls, sizeof (cls), 0); {用这一句将窗口类变量cls清零}<br> cls.lpfnWndProc := @DummyWindowProc; {取回调函数DummyWindowProc的地址}<br> cls.hInstance := hInstance; {实例句柄}<br> cls.lpszClassName := AppName; {窗口类名}<br> RegisterClass (cls); {注册窗口类cls}<br> { 现在可以创建程序的主窗口了-在本程序中是个虚拟窗口}<br> { Now create the dummy window }<br> Wnd := CreateWindow (AppName, AppName, ws_OverlappedWindow,0, 0, 100, 100,<br> 0, 0, hInstance, Nil);<br> x:= 0; {变量X其实是个开关变量,记录现在是否已经隐藏了桌面}<br> { 如果窗口创建成功,则显示窗口,并进入消息循环 }<br> if Wnd <> 0 then<br> begin<br> ShowWindow (Wnd, sw_Hide);{本例中窗口是隐藏的}<br> { 下面进入消息循环,该循环将不断运行直到 GetMessage返回0 }<br> while GetMessage (Msg, 0, 0, 0) do<br> begin<br> TranslateMessage (Msg);<br> DispatchMessage (Msg);<br> end;<br> end;<br>end;<br>{主程序}<br>begin<br>WinMain;<br>end.<br><br>