任务栏

Windows 界面包含一个名为任务栏的特殊应用程序桌面工具栏。 可以将任务栏用于在打开的窗口之间切换和启动新应用程序等任务。

注意

有关从 Windows 7 开始对任务栏所做的更改的信息,请参阅 任务栏扩展

 

本主题包含以下各节:

关于任务栏

任务栏包括以下内容:

  • “开始 ”菜单
  • (Windows Vista 及更早版本的快速启动栏仅)
  • 任务栏按钮
  • 工具栏 (可选)
  • 通知区域

开始 ”菜单包含可访问程序、文档和设置的命令。 这些命令包括“所有程序”、“文档”、“控制面板”、“游戏”、“帮助和支持”、“关闭”“搜索程序和文件”。

Windows 早期版本中的 “开始” 包含 查找运行等项,其功能包含在 Windows Vista 及更高版本的 搜索程序和文件中

快速启动栏在早于 Windows 7 的 Windows 版本中提供,其中包含应用程序的快捷方式。 Windows 提供默认条目(如 Windows Internet Explorer),用户可以添加他们选择的任何进一步快捷方式。 此区域中的图标会响应一次单击。 在 Windows 7 及更高版本中,此功能包含在任务栏按钮中。

每当应用程序创建无所有者窗口(即没有父窗口且具有相应扩展样式位的窗口)时,Shell 会在任务栏上放置一个按钮 (请参阅) 下面的 管理任务栏按钮。 若要切换到窗口,用户可单击其窗口按钮。 从 Windows 7 起,此功能已大大扩展。 有关详细信息,请参阅 任务栏扩展

应用程序可以在通知区域中放置图标,以指示操作的状态或向用户通知事件。 例如,应用程序可能会在通知区域中放置打印机图标,以显示打印作业正在进行。 但是,在 Windows 7 及更高版本中,通知区域以前提供的一些信息应通过应用程序的任务栏按钮提供。 如果任务栏是水平) ,则通知区域位于任务栏 (的右边缘;如果任务栏是垂直) ,则通知区域位于底部 (。 有关详细信息,请参阅 通知和通知区域

如果选择了该选项,通知区域还会显示当前时间。 该选项的查找方式如下:

  • Windows 7 及更高版本:“通知区域图标”控制面板应用程序的“打开或关闭系统图标”页面中的“时钟”下拉列表 (也可通过通知区域属性) 访问。
  • Windows Vista“任务栏”和“开始菜单”属性窗口的“通知区域”页中的“时钟检查”框。
  • Windows XP“任务栏”和“开始菜单”属性窗口中的“显示时钟检查”框。

用户可以右键单击任务栏以显示快捷菜单。 快捷菜单包括用于级联窗口、堆叠窗口、并行显示窗口、显示桌面、启动任务管理器和设置任务栏属性的命令。 快捷菜单还提供在任务栏中添加或删除一组工具栏的选项。 可以通过在“CATID_DeskBand”类别下注册新工具栏来向此菜单添加新工具栏。 有关详细信息,请参阅 实现带区对象。 请注意,从 Windows 7 起,任务栏和通知区域具有单独的快捷菜单。 这些快捷菜单共享一些选项,例如窗口排列,并添加其他选项。

任务栏显示选项

任务栏支持两种显示选项:“自动隐藏”和(仅在 Windows Vista 及更早版本中)Always On顶部 (任务栏在 Windows 7 及更高版本) 始终处于此模式。 若要设置这些选项,用户必须打开任务栏快捷菜单,单击“属性”,然后选中或清除“自动隐藏任务栏检查框或”将任务栏保留在其他窗口检查顶部“框。 若要检索这些显示选项的状态,请使用 ABM_GETSTATE 消息。 如果要在这些显示选项的状态发生更改时收到通知,请在窗口过程中处理 ABN_STATECHANGE 通知消息。 若要更改这些显示选项的状态,请使用 ABM_SETSTATE 消息。

工作区域是任务栏未遮挡的屏幕部分。 若要检索工作区的大小,请使用设置SPI_GETWORKAREA值调用 SystemParametersInfo 函数。 若要检索描述任务栏位置的矩形坐标,请使用 ABM_GETTASKBARPOS 消息。

可以通过使用 SetWindowPos 将窗口矩形的大小显式设置为等于屏幕大小来覆盖任务栏。 对于 Windows 2000 系统或更高版本,窗口必须缺少 WS_CAPTIONWS_THICKFRAME,否则窗口必须调整大小,使工作区覆盖整个屏幕。 此外,对于这些系统,如果任务栏设置为 Always On Top,则仅当应用程序是前台应用程序时,任务栏才会保持隐藏状态。

将快捷方式添加到“开始”菜单

若要将项添加到 Microsoft Windows NT 4.0、Windows 2000 及更高版本或 Windows 95 或更高版本上的“程序”子菜单,请执行以下步骤。

  1. 使用 IShellLink 接口创建 shell 链接。
  2. 使用 SHGetSpecialFolderLocation 获取 Programs 文件夹的 PIDL,并传递 CSIDL_PROGRAMS
  3. 将 Shell 链接添加到“程序”文件夹。 还可以在“程序”文件夹中创建一个文件夹,并将链接添加到该文件夹。

管理任务栏按钮

每当应用程序创建非所有窗口时,Shell 会在任务栏上创建一个按钮。 若要确保窗口按钮放置在任务栏上,请创建具有 WS_EX_APPWINDOW 扩展样式的无所有者窗口。 若要防止窗口按钮放置在任务栏上,请创建具有 WS_EX_TOOLWINDOW 扩展样式的无所有者窗口。 作为替代方法,可以创建一个隐藏窗口,并使此隐藏窗口成为可见窗口的所有者。

仅当窗口样式支持可见的任务栏按钮时,Shell 才会从任务栏中删除窗口的按钮。 如果要动态地将窗口的样式更改为不支持可见任务栏按钮的样式,必须先通过调用 ShowWindow (SW_HIDE) 来 隐藏窗口,然后更改窗口样式,然后显示窗口。

窗口按钮通常包含应用程序图标和标题。 但是,如果应用程序不包含系统菜单,则会创建不带图标的窗口按钮。

如果希望应用程序在窗口未处于活动状态时引起用户的注意,请使用 FlashWindow 函数让用户知道消息正在等待。 此函数闪烁窗口按钮。 用户单击窗口按钮激活窗口后,应用程序可以显示该消息。

修改任务栏的内容

Shell32.dll 版本 4.71 及更高版本添加了修改任务栏内容的功能。 现在可以在应用程序中添加、删除和激活任务栏按钮。 激活项目不会激活窗口;它会在任务栏上按压时显示项。

任务栏修改功能在组件对象模型 (COM) 对象 (CLSID_TaskbarList ) 中实现,该对象 (IID_ITaskbarList) 公开 ITaskbarList 接口。 必须调用 ITaskbarList::HrInit 方法来初始化对象。 然后,可以使用 ITaskbarList 接口的方法修改任务栏的内容。

在通知区域中添加、修改和删除图标

使用 Shell_NotifyIcon 函数在通知区域中添加、修改或删除图标。 Shell_NotifyIcondwMessage 参数是指向任务栏的消息,用于指定要执行的操作。 pnid 参数是指向 NOTIFYICONDATA 结构的指针,该结构用于标识图标并传递系统处理消息所需的任何其他信息。

可以使用通知区域图标执行以下操作。

  • 若要将图标添加到任务栏的通知区域,请调用 Shell_NotifyIcon ,并将 dwMessage 参数设置为 NIM_ADD。 NOTIFYICONDATA 结构用于指定图标的句柄和标识符,以及任何工具提示文本。 如果用户在任务栏属性中选择了“显示时钟检查”框,系统会将图标置于时钟的紧靠左侧。 否则,图标将显示在任务栏的右侧或底部。 任何现有图标都向左移动,为新图标腾出空间。
  • 若要修改图标的信息(包括图标句柄、工具提示文本和回调消息标识符),请调用 Shell_NotifyIcon ,并将 dwMessage 设置为 NIM_MODIFY。
  • 若要从通知区域删除图标,请调用 Shell_NotifyIcon ,并将 dwMessage 参数设置为 NIM_DELETE。

完成用户界面操作后,通过调用Shell_NotifyIcon将 dwMessage 设置为 NIM_SETFOCUS,将焦点返回到通知区域。 例如,当任务栏图标显示快捷菜单,但用户通过按 ESCAPE 键取消它时,可以执行此操作。

接收通知区域回调消息

应用程序通常会在任务栏的通知区域中放置图标,以用作状态指示器。 当用户执行鼠标操作时,可以提供其他信息,例如将鼠标指针移到图标上或单击图标。

系统通过发送与特定图标关联的应用程序定义的回调消息来通知鼠标和键盘事件。 这样,系统可以在用户(例如)单击图标或通过按键选择它时通知应用程序。

将图标添加到任务栏时,可以定义图标的回调消息。 回调消息标识符是在使用 NIM_ADD 传递的 NOTIFYICONDATA 结构的uCallbackMessage 成员中指定的。 发生事件时,系统会将回调消息发送到 由 hWnd 成员指定的窗口的窗口过程。 消息的 wParam 参数包含发生事件的任务栏图标的标识符。 lParam 参数保存与事件关联的鼠标或键盘消息。 例如,当鼠标指针移动到任务栏图标上时, lParam 包含 WM_MOUSEMOVE

各种鼠标事件的结果可以汇总如下:

  • 当用户将鼠标指针移到图标上时,系统将显示 NOTIFYICONDATA 中指定的工具提示文本。
  • 当用户单击该图标时,应用程序将收到 WM_LBUTTONDOWN 通知。
  • 当用户右键单击该图标时,应用程序将收到 WM_RBUTTONDOWN 通知。
  • 当用户双击该图标时,应用程序将收到 WM_LBUTTONDBLCLK 通知。

通常,单击图标会导致应用程序显示包含其他信息的窗口,右键单击会显示快捷菜单,双击执行默认快捷菜单命令。

有关如何更改与通知区域图标关联的工具提示文本的示例,请参阅 状态栏图标的气球工具提示

与 Windows NT 4.0、Windows 95 和 Windows 98 上发现的早期 Shell 版本不同,Shell 5.0 和更高版本以不同的方式Shell_NotifyIcon鼠标和键盘事件。 不同之处如下:

  • 如果用户使用键盘请求通知图标的快捷菜单,则 5.0 版 Shell 会向关联的应用程序发送 WM_CONTEXTMENU 消息。 早期版本发送 WM_RBUTTONDOWNWM_RBUTTONUP 消息。
  • 如果用户使用键盘选择通知图标并使用空格键或 Enter 键激活它,则 5.0 版本的 Shell 会向关联的应用程序发送 NIN_KEYSELECT 通知。 早期版本发送 WM_RBUTTONDOWNWM_RBUTTONUP 消息。
  • 如果用户使用鼠标选择通知图标并使用 Enter 键激活它,则 5.0 版本的 Shell 会向关联的应用程序发送 NIN_SELECT 通知。 早期版本发送 WM_RBUTTONDOWNWM_RBUTTONUP 消息。
  • 如果用户将鼠标指针传递到与之关联的图标上,则版本 6.0 Shell (Windows XP) 发送以下消息。
      • NIN_BALLOONSHOW - 显示气球时发送 (气球排队) 。
      • NIN_BALLOONHIDE - 在气球消失时发送,例如,删除图标时发送。 如果气球因超时或鼠标单击而关闭,则不会发送此消息。
      • NIN_BALLOONTIMEOUT - 由于超时而关闭气球时发送。
      • NIN_BALLOONUSERCLICK - 由于鼠标单击而关闭气球时发送。

可以通过调用将 dwMessage设置为NIM_SETVERSION 的 Shell_NotifyIcon 来选择 Shell 的行为方式。 设置 NOTIFYICONDATA 结构的 uVersion 成员以指示是想要版本 5.0 还是版本 5.0 之前的行为。

任务栏创建通知

在 Microsoft Internet Explorer 4.0 及更高版本中,Shell 会通知应用程序任务栏已创建。 创建任务栏时,它会向 TaskbarCreated 字符串注册消息,然后将此消息广播到所有顶级窗口。 当任务栏应用程序收到此消息时,它应假定它添加的任何任务栏图标已删除,然后再次添加它们。 此功能通常仅适用于 Shell 启动时已在运行的服务。 以下示例演示了一种非常简化的方法来处理这种情况。

在Windows 10上,当主显示器的 DPI 更改时,任务栏也会广播此消息。

LRESULT CALLBACK WndProc(HWND hWnd, 
                         UINT uMessage, 
                         WPARAM wParam, 
                         LPARAM lParam)
{
    static UINT s_uTaskbarRestart;

    switch(uMessage)
    {
        case WM_CREATE:
            s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
            break;
        
        default:
            if(uMessage == s_uTaskbarRestart)
                AddTaskbarIcons();
            break;
    }

    return DefWindowProc(hWnd, uMessage, wParam, lParam);
}

使用任务栏

本部分包含的示例演示如何向任务栏通知区域添加图标,以及如何处理任务栏图标的回调消息。

在通知区域中添加和删除任务栏图标

将图标添加到任务栏通知区域,方法是填写 NOTIFYICONDATA 结构,然后将结构传递到Shell_NotifyIcon,并将 dwMessage 设置为 NIM_ADD。 结构成员必须指定要添加图标的窗口的句柄,以及图标标识符和图标句柄。 还可以为图标指定工具提示文本。 如果需要接收图标的鼠标消息,请指定回调消息的标识符,系统应使用该标识符将消息发送到窗口过程。

以下示例中的 函数演示如何向任务栏添加图标。

// MyTaskBarAddIcon - adds an icon to the notification area. 
// Returns TRUE if successful, or FALSE otherwise. 
// hwnd - handle to the window to receive callback messages 
// uID - identifier of the icon 
// hicon - handle to the icon to add 
// lpszTip - tooltip text 

BOOL MyTaskBarAddIcon(HWND hwnd, UINT uID, HICON hicon, LPSTR lpszTip) 
{ 
    BOOL res; 
    NOTIFYICONDATA tnid; 
 
    tnid.cbSize = sizeof(NOTIFYICONDATA); 
    tnid.hWnd = hwnd; 
    tnid.uID = uID; 
    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; 
    tnid.uCallbackMessage = MYWM_NOTIFYICON; 
    tnid.hIcon = hicon; 
    if (lpszTip) 
        hr = StringCbCopyN(tnid.szTip, sizeof(tnid.szTip), lpszTip, 
                           sizeof(tnid.szTip));
        // TODO: Add error handling for the HRESULT.
    else 
        tnid.szTip[0] = (TCHAR)'\0'; 
 
    res = Shell_NotifyIcon(NIM_ADD, &tnid); 
 
    if (hicon) 
        DestroyIcon(hicon); 
 
    return res; 
}

若要从任务栏通知区域删除图标,请填充 NOTIFYICONDATA 结构,并使用 dwMessage 设置为 NIM_DELETE 调用Shell_NotifyIcon。 删除任务栏图标时,请仅指定结构的 cbSizehWnduID 成员。 例如:

// MyTaskBarDeleteIcon - deletes an icon from the notification area. 
// Returns TRUE if successful, or FALSE otherwise. 
// hwnd - handle to the window that added the icon. 
// uID - identifier of the icon to delete. 

BOOL MyTaskBarDeleteIcon(HWND hwnd, UINT uID) 
{ 
    BOOL res; 
    NOTIFYICONDATA tnid; 
 
    tnid.cbSize = sizeof(NOTIFYICONDATA); 
    tnid.hWnd = hwnd; 
    tnid.uID = uID; 
         
    res = Shell_NotifyIcon(NIM_DELETE, &tnid); 
    return res; 
}

接收鼠标事件

如果为任务栏图标指定回调消息,则每当鼠标事件发生在图标的边框中时,系统就会将消息发送到应用程序。 消息的 wParam 参数指定任务栏图标的标识符,消息的 lParam 参数指定系统由于鼠标事件生成的消息。

以下示例中的函数来自将电池和打印机图标添加到任务栏的应用程序。 应用程序在收到回调消息时调用函数。 函数确定用户是否已单击其中一个图标,如果发生单击,则调用应用程序定义的函数来显示状态信息。

// On_MYWM_NOTIFYICON - processes callback messages for taskbar icons. 
// wParam - first message parameter of the callback message. 
// lParam - second message parameter of the callback message. 

void On_MYWM_NOTIFYICON(WPARAM wParam, LPARAM lParam) 
{ 
    UINT uID; 
    UINT uMouseMsg; 
 
    uID = (UINT) wParam; 
    uMouseMsg = (UINT) lParam; 
 
    if (uMouseMsg == WM_LBUTTONDOWN) 
    { 
        switch (uID) 
        { 
            case IDI_MYBATTERYICON: 
 
                // The user clicked the battery icon. Display the 
                // battery status. 
                ShowBatteryStatus(); 
                break; 
 
            case IDI_MYPRINTERICON: 
 
                // The user clicked the printer icon. Display the 
                // status of the print job. 
                ShowJobStatus(); 
                break; 
 
            default: 
                break; 
        } 
     } 

     return; 
 }