65.9K
CodeProject 正在变化。 阅读更多。
Home

Win32 中 Shell_NotifyIcon 的基本用法

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (50投票s)

2003年8月16日

3分钟阅读

viewsIcon

481196

downloadIcon

16306

在系统托盘上最小化启动您的应用程序。

引言

最近,我在浏览 CodeProject,寻找一个如何管理系统托盘图标的简单例子。 哎呀,对不起,我不应该称它们为托盘图标,正如 MSDN 文档如此仔细地指出

"任务栏通知区域有时会错误地称为托盘。"

尽管如此,我还是会坚持把铲子叫做铲子,并将“任务栏通知区域”称为“托盘”,“任务栏通知区域图标”称为“托盘图标”。 无论如何,回到正题,为什么还要写一篇关于托盘图标的文章呢?

  • 我以前从未写过 Code Project 文章,这似乎很容易。
  • 这不是另一个封装器,而是一个简单的直接的 Shell_NotifyIcon 示例,代码量最少。
  • 我想要一个用纯 Win32 代码编写的例子。
  • 我想解决我在其他关于该主题的文章中看到的一些常见问题。

基础知识

添加、修改、隐藏和删除托盘图标分两步完成

  1. 初始化 NOTIFYICONDATA 结构
  2. 调用 Shell_NotifyIcon

初始化 NOTIFYICONDATA 结构

// zero the structure - note: Some Windows funtions
// require this but I can't be bothered to remember
// which ones do and which ones don't.


    NOTIFYICONDATA niData; 
    ZeroMemory(&niData,sizeof(NOTIFYICONDATA));


// get Shell32 version number and set the size of the
// structure note: the MSDN documentation about this is
// a little dubious(see bolow) and I'm not at all sure
// if the code bellow is correct


    ULONGLONG ullVersion =
        GetDllVersion(_T("Shell32.dll"));

    if(ullVersion >= MAKEDLLVERULL(6,0,0,0))
        niData.cbSize = sizeof(NOTIFYICONDATA);

    else if(ullVersion >= MAKEDLLVERULL(5,0,0,0))
        niData.cbSize = NOTIFYICONDATA_V2_SIZE;

    else niData.cbSize = NOTIFYICONDATA_V1_SIZE;


// the ID number can be any UINT you choose and will
// be used to identify your icon in later calls to
// Shell_NotifyIcon


    niData.uID = MY_TRAY_ICON_ID;


// state which structure members are valid
// here you can also choose the style of tooltip
// window if any - specifying a balloon window:
// NIF_INFO is a little more complicated 


    niData.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;


// load the icon note: you should destroy the icon
// after the call to Shell_NotifyIcon


    niData.hIcon =
        (HICON)LoadImage( hInstance,
            MAKEINTRESOURCE(IDI_MY_ICON),
            IMAGE_ICON,
            GetSystemMetrics(SM_CXSMICON),
            GetSystemMetrics(SM_CYSMICON),
            LR_DEFAULTCOLOR);


// set the window you want to recieve event messages


    niData.hWnd = hWnd;


// set the message to send
// note: the message value should be in the
// range of WM_APP through 0xBFFF


    niData.uCallbackMessage = MY_TRAY_ICON_MESSAGE;

调用 Shell_NotifyIcon

// NIM_ADD adds a new tray icon
    Shell_NotifyIcon(NIM_ADD,&niData);

隐形对话框

我看到很多帖子问如何最小化对话框应用程序到系统托盘开始,因此得名 Stealth Dialog。 这可以通过首先创建一个非模态对话框来实现

    HWND hWnd = CreateDialog( hInstance,
        MAKEINTRESOURCE(MY_DIALOG),
        NULL,
        (DLGPROC)MyDlgProc );

然后使用上面显示的 Shell_NotifyIcon 将您的图标添加到托盘。 不要调用 ShowWindow

菜单和消息

来自托盘的消息将发送到由 NOTIFYICONDATA structhWnd 成员指定的窗口,消息 ID 由 uCallbackMessage 成员指定(见上文)。 具体消息在 LPARAM 中。

INT_PTR CALLBACK MyDlgProc(HWND hWnd, UINT message,
    WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case MY_TRAY_ICON_MESSAGE:
        switch(lParam)
        {
        case WM_LBUTTONDBLCLK:
            ShowWindow(hWnd, SW_RESTORE);
            break;
        case WM_RBUTTONDOWN:
        case WM_CONTEXTMENU:
            ShowContextMenu(hWnd);
        }
        break;
    case...

如果您实现上下文菜单,则通过 WM_COMMAND 接收消息,菜单项 ID 包含在 WPARAM 的低位字中。

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case MY_MENU_MSG1:
            ...
            break;
        case MY_MENU_MSG2:
        ...

重要提示:如果您实现了上下文菜单,那么在调用 TrackPopupMenu 之前,务必将窗口设置为前台,以确保菜单正确关闭。

void ShowContextMenu(HWND hWnd)
{
    ...

    HMENU hMenu;

// create or load a menu

    ...

    SetForegroundWindow(hWnd);
    TrackPopupMenu(hMenu, ...

清理

在您的应用程序关闭之前,您应该使用 NIM_DELETE 标志调用 Shell_NotifyIcon 来删除您的托盘图标。

    case WM_DESTROY:
        Shell_NotifyIcon(NIM_DELETE,&niData);

注释

MSDN 文档中关于 NOTIFYICONDATA 结构的 cbSize 成员的说明

"您可以通过适当地设置 NOTIFYICONDATA 结构的大小,使您的应用程序与所有 Shell32.dll 版本兼容,同时仍然使用当前的头文件。在初始化该结构之前,使用 DllGetVersion 函数来确定系统上安装了哪个 Shell32.dll 版本。 如果它是 5.0 或更高版本,请使用以下代码初始化 cbSize 成员:

nid.cbSize = sizeof(NOTIFYICONDATA);

cbSize 设置为此值会启用所有 5.0 和 6.0 版本的增强功能。 对于早期版本,pre-6.0 结构的大小由 NOTIFYICONDATA_V2_SIZE 常量给出,pre-5.0 结构的大小由 NOTIFYICONDATA_V1_SIZE 常量给出。 使用以下代码初始化 cbSize 成员:

nid.cbSize = NOTIFYICONDATA_V2_SIZE;

将此值用于 cbSize 可以使您的应用程序使用具有早期 Shell32.dll 版本的 NOTIFYICONDATA ,尽管没有 6.0 版本的增强功能:"

现在也许是我的邻居的土耳其烟草,或者我只是没有抓住重点,但“5.0 或更高版本”和“pre-6.0”之间似乎存在重叠冲突。

无论如何,如果有人可以对此或其他他们想阐明的事情有所启发,请阐明。

© . All rights reserved.