多语言展示
当前在线:1238今日阅读:167今日分享:16

windows sdk编程(托盘编程)

如今,windows的托盘相信大家都不会陌生,任何需要长时间运行的程序比如播放器、杀毒软件等大量采用托盘图标,那么它是怎么实现的呢,其实很容易,本文从最基本的sdk编程讲起,这是一个简单的windows托盘编程,纯sdk编程,不用到第三方的库文件,环境无所谓,笔者用的是visual studio 2013,首先它有一个简单的窗体,在窗体最小化的时候托盘就会自动显示,当然,为了更具实用性,右键托盘图标也会有弹出菜单,具体请看如下.(如果觉得好还请点赞 >_<)
工具/原料
1

winOS

2

visual studio系列

方法/步骤
1

系统托盘是指任务条中的一个方形区域, 在该区域中可以放入一些小图标, 通常您可以在此处看到系统提供的最新时间。 您自己当然也可以把快捷小图标放到此处。 下面是这么做的步骤:1. 设置 NOTIFYICONDATA 型的结构体变量的成员变量的值:o cbSize 该结构体的大小。o hwnd 窗口的句柄。 当鼠标滑过该小图标时, 该窗口将接收到相关的消息。o uID 小图标的 ID 号。 您可以取任意值, 只是当您的应用程序有不止一个小图标时, 您要能够区分出到底是那一个小图标接收到了鼠标的消息, 也即 ID 号必须唯一。o uFlags 指定该结构体变量的那些成员变量有效。 NIF_ICON 有效。 NIF_MESSAGE 有效。 NIF_TIP 有效。o uCallbackMessage 自定义的消息。 当鼠标对小图标动作时, WINDOWS 外壳将把该消息发送到您的应用程序。 该消息的值您可以自己定义。o hIcon 放入系统托盘中的图标的句柄。o szTip  64 字节的缓冲区, 它用来放入提示字符串 , 当鼠标停留在小图标上时, 就会显示该字符串 。2. 调用 Shell_NotifyIcon 函数。 该函数在 shell32.inc 中定义, 其原型如下:           BOOL Shell_NotifyIcon( DWORD dwMessage,  PNOTIFYICONDATA lpdata ); dwMessage 是发送到 WINDOWS 外壳的消息:NIM_ADD 把小图标加到系统托盘区。NIM_DELETE 从系统托盘中删除小图标。NIM_MODIFY 修改小图标。lpdata 是指向 NOTIFYICONDATA 型结构体变量的指针。如果您想要加入一个小图标就用 NIM_ADD, 删除时使用 NIM_DELETE 消息。基本上的消息就是这些。 但是大多数的情况下, 您不会仅仅满足把一个小图标放到那里。 您还必须要对鼠标事件作出适当的反应。 您可以在 NOTIFYICONDATA 型的结构体变量的成员变量 uCallbackMessage 中设置您要处理的消息, 然后 WINDOWS 外壳将在发生这些事件时通知您的应用程序。 随着消息传送的参数 wParam 和 lParam 的值如下: wParam 小图标的 ID 号。 它和您在 NOTIFYICONDATA 型结构体变量中的成员变量 uID 中设置的值一样。 lParam 低字包含鼠标消息。 譬如, 用户在小图标上按下了右键时, lParam 中将包含 WM_RBUTTONDOWN 消息。大多数的系统托盘中的小图标, 在用户用鼠标右击时都会弹出一个菜单以方便用户选择。 我们可先创建菜单, 然后调用TrackPopupMenu 函数来显示它。 步骤如下:1. 调用 CreatePopupMenu 函数来创建菜单。 该函数创建一个空的菜单。 如果成功, 将返回该菜单的句柄。2. 调用 AppendMenu, InsertMenu 或 InsertMenuItem 来向菜单中加入菜单项。3. 当您想在当前鼠标位置显示该菜单时, 调用 GetCursorPosition 函数来得到鼠标当前的屏幕位置, 然后调用TrackPopupMenu 来显示菜单。 当用户从弹出式菜单中选择了一个菜单项时, WINDOWS 将发送 WM_COMMAND 消息给您应用程序的消息处理过程, 这和通常的菜单选择是一样的。 .注意: 当您使用系统托盘中的小图标时有两件比较讨厌的事:1. 该菜单可能不会像通常那样马上消失掉。 这是因为从弹出式接收消息的窗口必须是前景窗口 。 调用 SetForegroundWindow函数就可以纠正该错误;2. 在调用了 SetForegroundWindow 函数后, 您会发现第一次该弹出式菜单会正常弹出而且工作的很好。 但是随后, 该菜单只是一弹出就立即消失。 根据 MSDN, 这么做是故意的。 为了使得弹出菜单保持住, 必须要求下一个切换到的是程序的主窗口 。 您可以通过邮寄任何消息给该程序的窗口来强行进行任务切换。 注意要使用 PostMessage 而不是 SendMessage

2

完整示例程序:#include 'Windows.h'#include 'tchar.h'#define WM_SHELLNOTIFY WM_USER+5#define IDI_TRAY 0#define IDM_RESTORE 1000#define IDM_EXIT    1010TCHAR ClassName[] = _T('TrayIconWinClass');TCHAR AppName[] = _T('TrayIcon Demo');TCHAR RestoreString[] = _T('&Restore');TCHAR ExitString[] = _T('E&xit Program');HINSTANCE g_hInstance;NOTIFYICONDATA note;HMENU   hPopupMenu; INT_PTR CALLBACK ProcWinMain(   HWND hWnd,                       UINT Msg,                       WPARAM wParam,                       LPARAM lParam){    POINT pt;    switch(Msg)    {    case WM_CREATE:    {        hPopupMenu = CreatePopupMenu();        AppendMenu(hPopupMenu,MF_STRING,IDM_RESTORE,RestoreString);        AppendMenu(hPopupMenu,MF_STRING,IDM_EXIT,ExitString);    }    break;       case WM_DESTROY:        PostQuitMessage(0);        break;    case WM_SIZE:        if(wParam == SIZE_MINIMIZED)        {            note.cbSize = sizeof(NOTIFYICONDATA);            note.hWnd = hWnd;            note.uID = IDI_TRAY;            note.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;            note.uCallbackMessage = WM_SHELLNOTIFY;            note.hIcon = LoadIcon(NULL,IDI_WINLOGO);            lstrcpy(note.szTip,AppName);            ShowWindow(hWnd,SW_HIDE);            Shell_NotifyIcon(NIM_ADD,¬e);        }        break;    case WM_COMMAND:        if(lParam == 0)        {            Shell_NotifyIcon(NIM_DELETE,¬e);            if(LOWORD(wParam) == IDM_RESTORE)                ShowWindow(hWnd,SW_RESTORE);            else                DestroyWindow(hWnd);        }        break;   case WM_SHELLNOTIFY:        if(wParam == IDI_TRAY)        {            if(lParam == WM_RBUTTONDOWN)            {                GetCursorPos(&pt);                TrackPopupMenu(hPopupMenu,TPM_RIGHTALIGN,pt.x,                    pt.y,NULL,hWnd,NULL);                        }            else if(lParam == WM_LBUTTONDBLCLK)            {                SendMessage(hWnd,WM_COMMAND,IDM_RESTORE,0);            }        }        break;    default:        return DefWindowProc(hWnd,Msg,wParam,lParam);    }    return 0;}int WINAPI WinMain(     HINSTANCE hInstance,                        HINSTANCE hPrevInstance,                        LPSTR lpCmdLine,                        int nCmdShow){    WNDCLASSEX wc;    MSG msg;    HWND hWnd;    g_hInstance = hInstance;    wc.cbSize = sizeof(WNDCLASSEX);    wc.style = CS_HREDRAW | CS_VREDRAW |CS_DBLCLKS;    wc.lpfnWndProc = ProcWinMain;    wc.cbClsExtra = NULL;    wc.cbWndExtra = NULL;    wc.hInstance = hInstance;    wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE);    wc.lpszMenuName = NULL;    wc.lpszClassName = ClassName;    wc.hIcon = wc.hIconSm = LoadIcon(NULL,IDI_APPLICATION);    wc.hCursor = LoadCursor(NULL,IDC_ARROW);    RegisterClassEx(&wc);   hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,ClassName,AppName,WS_OVERLAPPEDWINDOW,        CW_USEDEFAULT,CW_USEDEFAULT,350,200,NULL,NULL,hInstance,NULL);    ShowWindow(hWnd,SW_SHOWNORMAL);    UpdateWindow(hWnd);   while(GetMessage(&msg,NULL,0,0))    {        TranslateMessage(&msg);        DispatchMessage(&msg);    }   return msg.wParam;}

3

难点分析:该程序将显示一个简单的窗口 。 当您按下最小化按钮时, 该窗口将隐藏, 然后放一个小图标到系统托盘中。 当您双击小图标时,应用程序将恢复自己, 并把小图标从系统托盘中删除。 当您右击小图标时, 会显示一个弹出式菜单。 您可以在菜单中选择是恢复窗口还是退出应用程序。    case WM_CREATE:   {        hPopupMenu = CreatePopupMenu();        AppendMenu(hPopupMenu, MF_STRING,IDM_RESTORE,RestoreString);        AppendMenu(hPopupMenu,MF_STRING,IDM_EXIT,ExitString);   }   break;当主窗口创建时, 将会创建一个弹出式菜单, 并且加入两个菜单项。  AppendMenu 的语法如下:BOOL AppendMenu( HMENU hMenu,  UINT uFlags, UINT_PTR uIDNewItem,LPCTSTR lpNewItem ); hMenu 是将要加入菜单项的菜单的句柄。 uFlags 告诉 WINDOWS 要加入的菜单项是位图、 字符串或自画的项目以及是可用、 不可用或灰色显示等。 您可以从WIN32 API 指南中得到全部的标志位的信息。 在我们的例子中使用标志位 MF_STRING, 它表示我们加入的菜单项是字符串 。 uIDNewItem 是菜单项的 ID 号。 这是一个用户自定义的值, 它用来唯一地代表菜单项。 . lpNewItem 用来指定菜单项的内容, 具体代表什么取决于 uFlags 中指定的标志。 我们前面指定了 MF_STRING 标志,所以此处代表一个字符串主窗口创建完成后, 用户就可以开始测试了 。 这时按下最小化键。当一个窗口被最小化时将接收到 WM_SIZE 消息, 其中 wParam 参数中的值为 SIZE_MINIMIZED。case WM_SIZE:        if(wParam == SIZE_MINIMIZED)        {            note.cbSize = sizeof(NOTIFYICONDATA);            note.hWnd = hWnd;            note.uID = IDI_TRAY;            note.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;            note.uCallbackMessage = WM_SHELLNOTIFY;            note.hIcon = LoadIcon(NULL,IDI_WINLOGO);            lstrcpy(note.szTip,AppName);            ShowWindow(hWnd,SW_HIDE);            Shell_NotifyIcon(NIM_ADD,¬e);        }        break;这时我们来给 NOTIFYICONDATA 型结构体变量赋值。 IDI_TRAY 是在代码开始处定义的一个数值常量, 您可以任意设定它的值。由于我们仅有一个图标, 所以这一点并不重要, 如果要同时加入几个系统图标的话, 那么每个图标都要有一个唯一的 ID 号。 由于我们指定了一个图标 NIF_ICON, 所以我们要在 uFlags 成员变量中指定所有的标志位, 我们还指定了一个自定义的消息NIF_MESSAGE 和帮助文本 NIF_TIP。  WM_SHELLNOTIFY 被定义为 WM_USER+5, 只要是唯一的值, 就无所谓是多少了 , 只要大于WM_USER。 我们这里用的是 WINDOWS 登录时的图标, 当然您可以使用任意您想要用的图标, 您可以用 LoadIcon 函数从资源中装载, 该函数返回一个图标的句柄。 最后我们在 szTip 中放入当鼠标放在图标时显示的提示文本。 为了达到“ 最小化然后只显示图标的效果” , 我们在这时隐藏掉主窗口 。接下来, 我们调用 Shell_NotifyIcon 函数并指定标志位 NIM_ADD 把图标加到系统托盘中去。现在我们的主窗口隐藏了 , 图标显示在系统托盘中。 如果您让鼠标从图标上滑过, 将看到提示文本。 如果您双击小图标, 主窗口就会显示, 图标将消失。    case WM_SHELLNOTIFY:        if(wParam == IDI_TRAY)        {            if(lParam == WM_RBUTTONDOWN)            {                GetCursorPos(&pt);                TrackPopupMenu(hPopupMenu,TPM_RIGHTALIGN,pt.x,                    pt.y,NULL,hWnd,NULL);                        }            else if(lParam == WM_LBUTTONDBLCLK)            {                SendMessage(hWnd,WM_COMMAND,IDM_RESTORE,0);            }        }        break;当在系统托盘中的图标发生鼠标事件时, 您的窗口将接收到 WM_SHELLNOTIFY 消息, 该消息是在 uCallbackMessage 成员变量中指定的。 在接收到该消息时, wParam 中包含了图标的 ID 号, lParam 中包含了鼠标动作的原始数据。 在上面的代码中, 我们首先检测是否是我们感兴趣的消息。 如果是的话, 我们在看看是什么消息。 因为我们只对右击和双击事件感兴趣, 所以我们仅仅处理 WM_RBUTTONDOWN 和 WM_LBUTTONDBLCLK 消息。如果是 WM_RBUTTONDOWN, 我们调用 GetCursorPos 来得到鼠标光标所在的当前屏幕位置。 注意我指的是屏幕位置, 即, 其坐标是相对于整个的屏幕的。 譬如, 如果屏幕的解析读 640*480, 那么它的右下角的坐标是 x==639 , y==479。 如果您想要把屏幕位置转换成窗口的坐标, 可以调用 ScreenToClient 函数我们想要在当前的位置显示弹出式菜单, 我们就调用 TrackPopupMenu 函数, 该函数需要屏幕的坐标, 由 GetCursorPos 函数返回的坐标就可以原封不动的拿过来用。TrackPopupMenu 的原型如下:BOOL TrackPopupMenu( HMENU hMenu,  UINT uFlags,  int x,  int y,  intnReserved,  HWND hWnd,  HWND prcRect ); hMenu 是弹出式菜单的句柄。 uFlags 功能的选择。 像在哪里放置( 相对于随后将指定的坐标) 菜单, 那一个鼠标按钮用来跟踪弹出式菜单。 在我们的例子中, 我们用 TPM_RIGHTALIGN 标志位来指定弹出式菜单放在坐标的左边。 x 和 y 指定放置菜单的屏幕坐标。 nReserved 必须为 NULL。 hWnd 是将要接收消息的窗口的句柄。 prcRect 指定一个矩形区域。 如果在该矩形区域外面按下鼠标的话, 菜单将消失。 一般我们把该值设为 NULL, 这样当用户只要在菜单外面按下鼠标, 菜单立即消失。当用户双击图标时, 我们给我们自己的窗口发送 WM_COMMAND 消息, 并指定消息为 IDM_RESTORE, 这样可以达到和在弹出式菜单中选择“Restore” 菜单项同样的效果。 为了能够接收到双击消息, 主窗口必须要有的 CS_DBLCLKS 风格。    case WM_COMMAND:        if(lParam == 0)        {            Shell_NotifyIcon(NIM_DELETE,¬e);            if(LOWORD(wParam) == IDM_RESTORE)                ShowWindow(hWnd,SW_RESTORE);            else                DestroyWindow(hWnd);        }        break;当用户选择恢复主窗口时, 我们调用 Shell_NotifyIcon 函数来删除掉系统托盘中的图标, 这一次我们要指定 NIM_DELETE 消息。接下来我们把主窗口恢复到原始的状态。 如果用户选择了 Exit 菜单项, 我们不但把图标给删除掉, 也从整个的应用程序中退出

注意事项
1

版权所有,转载请注明本网址哦

2

有问题欢迎大家私信给我,觉得好别忘了点赞哈

推荐信息