`
mmdev
  • 浏览: 13301576 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

在 Windows 应用程序中使用 Windows XP 的外观风格和 PrintWindow

阅读更多
在 Windows 应用程序中使用 Windows XP 的外观风格和 PrintWindow

下载示例代码 单击此处下载示例 - TaskSwitch.exe

<!--END SAMPLE-->

Paul Hellyar
Microsoft Corporation
2001年10月25日

MSDN Downloads(英文)下载本文的示例应用程序。

注意:此示例仅适用于运行 Windows XP 的计算机。打开示例并打开两个或多个应用程序窗口之后,请使用 AltTab 功能键来运行 TaskSwitcher 应用程序。

摘要:本文介绍了一种增强的 AltTab 应用程序 TaskSwitcher,并以此为框架演示了在 Windows 应用程序中使用 Windows XP 新的外观风格和 PrintWindow 的方法。

目录

简介

Microsoft® Windows® XP 引入了一种新的外观风格,它使用方便,并且用户界面也更加丰富。例如,圆角窗口、更具质感的任务栏以及将鼠标悬停在 UI 元素上时,可实现 UI 元素的热跟踪。

图 1:新外观风格中的 Calculator(计算器)和 Display Properties(显示属性)对话框

Windows XP 还引入了新的打印 API:PrintWindow(英文)。该 API 允许调用者制作窗口的快照并将其插入设备环境。

有关外观风格以及将其应用于应用程序的介绍,请参阅 MSDN Library 中的技术文章“使用 Windows XP 的外观风格”。该文章提供了相关的概述和介绍信息,而本文的主要目的是提供一个使用外观风格 API 和 PrintWindow API 的实例。本文还为使用某些以前的 Win32 API 提供了一个刷新程序。

本文将特别阐述 TaskSwitcher 应用程序,它与目前 Windows 中已有的 AltTab 机制具有相同的功能。除了显示图标列表外,该应用程序还将显示将要切换到的应用程序的缩略图预览。显示应用程序图标和预览的容器窗口将通过外观风格 API 显示出来,使应用程序的外观符合最终用户当前选择的外观风格。

TaskSwitcher 应用程序

TaskSwitcher 是为代替 Windows XP 的现有 AltTab 应用程序切换机制而设计的。AltTab 是内置的 Windows 超级用户功能,它使最终用户能够在顶层应用程序窗口之间进行快速切换。当按下热键组合 Alt+Tab 时,Windows 会生成最终用户正在使用的已打开窗口的列表。已打开窗口的列表将以一组图标的形式显示,其中一个图标带有矩形的选择边框。当最终用户继续按住 Alt 键并按下 Tab 键时,矩形选择框将移至下一个图标。释放 Alt 键后,Windows 将把选定的图标所代表的应用程序置于前台。

图 2:Windows XP AltTab 容器窗口

此功能在逻辑上可以分成三个部分:首先,应用程序必须侦听组合键 Alt+Tab;接收到该组合键时,应用程序需要枚举桌面上的顶层应用程序窗口;最后,应用程序需要在某种 UI 容器中显示这些窗口,使用户可以选择要切换到的应用程序的图标。

截取键盘输入

使用 Win32 API,您可以通过几种方法之一创建侦听特定击键的应用程序。最简单的方法是使用 API RegisterHotKey(英文)。该 API 包含一个 hwnd、一个 ID、一个虚拟键和一个组合键。如果此调用成功,则无论何时按下虚拟键和组合键,hwnd 的 WndProc 都会收到一个 WM_HOTKEY 消息,该消息的 wParam 等于 ID。无论侦听应用程序窗口是否处于活动状态,都是如此。无论何时按下 AltTab,下面的调用都会使 hwndApp 收到一条 WM_HOTKEY 消息:

RegisterHotKey(hwndApp, IDH_ALTTAB, MOD_ALT, VK_TAB)

在 Windows XP 之前,无法将 AltTab 注册为热键。在 Windows XP 中,您不仅可以成功地将 AltTab 注册为热键,而且 Windows XP 还使您可以自己处理该事件,而不用启动其自身内置的 AltTab 热键处理程序。

// 创建一个侦听热键的虚拟窗口
HWND hwndApp = CreateWindow(WC_APP, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 
               NULL, THIS_EXE, NULL);
if (hwnd)
{
    // 注册 Alt+Tab
    RegisterHotKey(hwndApp, IDH_NEXT, MOD_ALT, VK_TAB);
    RegisterHotKey(hwndApp, IDH_PREV, MOD_ALT|MOD_SHIFT, VK_TAB);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

LRESULT WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_HOTKEY:
        {
            switch (wParam)
            {
                // 如果未显示容器窗口,则枚举
                // 顶层窗口,提取图标和文本,
                // 并将其显示在容器窗口中
                case IDH_NEXT:
                {
                    // 在窗口层次结构中选择
                    // 下一个顶层窗口的图标
                    break;
                }
                case IDH_PREV:
                {
                    // 在窗口层次结构中选择
                    // 上一个顶层窗口的图标
                }
            }
        }
    }
}

第二种实现键盘侦听的更高级的方法是同时使用 API SetWindowsHookEx(英文)和 WH_KEYBOARD_LL。该方法在当前桌面的全局范围内创建一个低级别的键盘挂钩层。在调用 SetWindowsHookEx 时指定的 LowLevelKeyboardProc 回调函数将接收所有的键盘输入。处理完键盘输入后,LowLevelKeyboardProc 应调用 CallNextHookEx 以使下一个挂钩链(很可能是目标应用程序)能够接收输入。由于 LowLevelKeyboardProc 接收了所有的键盘事件,因此可以很容易地将其用作一个状态机,用于侦听同时按下的 Alt 和 Tab 组合键。如果该应用程序实现它自己的 AltTab 机制,则此时将执行窗口枚举算法,并从 LowLevelKeyboardHook 中返回而不把最后的 AltTab 键事件转给其他应用程序。

hhook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hinst, 0);

LRESULT LowLevelKeyboardProc(INT nCode, WPARAM wParam, LPARAM lParam)
{
    static BOOL fShiftPressed = FALSE;

    BOOL fHandled = FALSE;

    if (nCode == HC_ACTION)
    {
        KBDLLHOOKSTRUCT *pkbdllhook = (KBDLLHOOKSTRUCT *)lParam;

        switch (wParam)
        {
            case WM_SYSKEYDOWN:
                switch (pkbdllhook->vkCode)
                {
                    case VK_LSHIFT:
                    case VK_RSHIFT:
                    {
                        // 用户按下 Shift 键
                        fShiftPressed = TRUE;
                        break;
                    }
                    case VK_TAB:
                    {
                        if (pkbdllhook->flags & LLKHF_ALTDOWN)
                        {
                            // 用户按下 Alt+Tab,执行 AltTab 热键处理程序
                            fHandled = TRUE;
                        }
                        break;
                    }
                    case VK_ESCAPE:
                    {
                        if (pkbdllhook->flags & LLKHF_ALTDOWN)
                        {
                            // 用户按下 Esc 键,关闭 AltTab 容器窗口 
                            // 并且不切换到选定窗口
                            fHandled = TRUE;
                        }
                        break;
                    }
                }

                break;

            case WM_KEYUP:
            case WM_SYSKEYUP:
                switch (pkbdllhook->vkCode)
                {
                    case VK_LMENU:
                    case VK_RMENU:
                    {
                        // 用户释放 Alt 键,关闭 AltTab 容器窗口
                        // 并切换到选定窗口
                        break;
                    }
                    case VK_LSHIFT:
                    case VK_RSHIFT:
                    {
                        // 用户释放 Shift 键
                        fShiftPressed = FALSE;
                        break;
                    }
                }

                break;
        }
    }

    return (fHandled ? TRUE : CallNextHookEx(hhook, nCode, wParam, lParam));
}

枚举顶层应用程序窗口

使用 Win32 API EnumWindows(英文)可以直接枚举顶层应用程序窗口。这个 API 接受 EnumFunc 回调函数作为参数。对于桌面上的每个顶层窗口,系统将用顶层窗口的窗口句柄作为参数,来调用 EnumFunc 函数。并不是所有的顶层窗口都应显示在 AltTab 列表中。需要查询窗口的一些属性,并且必须满足几个条件:窗口是应用程序窗口吗?窗口能被激活吗?窗口可视吗?窗口是 ToolWindow 吗?

接收到 AltTab 事件之后,TaskSwitcher 便开始使用 EnumWindows 枚举桌面上的顶层窗口。系统为每个顶层窗口调用回调函数。满足条件的窗口将被添加到窗口列表中,并显示在 AltTab 列表中。

显示顶层应用程序窗口

在 AltTab 列表的 UI 显示中,TaskSwitcher 使用了很多 Windows XP 的新编程功能。它使用新的 API DrawShadowText 来显示选定的应用程序的文本,使用新的 API PrintWindow 来生成窗口预览。最后,而且也许是应用程序开发人员最感兴趣的,TaskSwitcher 使用了 Windows XP 的新外观风格。

收集窗口信息

生成要在 AltTab 列表中显示的窗口列表后,会检索列表中每个窗口的各种属性并将其显示在预览容器中。通过向该窗口发送一个 WM_GETICON(英文)窗口消息,在列表中显示每个窗口的图标。当用户按 Tab 键在列表中移动时,列表中选定的应用程序图标的图标和文本将显示在预览容器的顶部。通过使用 API GetWindowText(英文)来检索每个窗口的标题文本。有趣的是,它使用了新的 API comctl32 v6 API DrawShadowText(英文)来显示应用程序文本。该 API 是 Windows XP 的新增功能,采用了 API DrawText 的所有相同参数,还有两个表示文本颜色和阴影颜色的 COLORREF 参数,以及阴影的 x 偏移量和 y 偏移量。

绘制窗口预览

TaskSwitcher 还可以显示选定窗口的缩略图预览。(除非最小化所预览的窗口,因为此时将只显示该窗口的标题栏。)绘制缩略图预览时,TaskSwitcher 采用了一些高级的 Win32 绘图技术,例如双重缓冲和半色调缩放等。然而,获取窗口预览的核心技术是新的 Windows XP user32 API PrintWindow。PrintWindow 带有一个窗口句柄、一个 hdc 和一个保留标志。该 API 使用窗口重定向,将窗口的快照绘制到 hdc 中。

// 制作窗口 hwnd 的快照,该窗口存储在内存设备环境 hdcMem 中
HDC hdc = GetWindowDC(hwnd);
if (hdc)
{
    HDC hdcMem = CreateCompatibleDC(hdc);
    if (hdcMem)
    {
        RECT rc;
        GetWindowRect(hwnd, &rc);

        HBITMAP hbitmap = CreateCompatibleBitmap(hdc, RECTWIDTH(rc), RECTHEIGHT(rc));
        if (hbitmap)
        {
            SelectObject(hdcMem, hbitmap);

            PrintWindow(hwnd, hdcMem, 0);

            DeleteObject(hbitmap);
        }
        DeleteObject(hdcMem);
    }
    ReleaseDC(hwnd, hdc);
}

使用外观风格 API 来显示容器

所有这些都绘制在容器窗口上。容器窗口的背景体现了 Windows XP 的新外观风格。也就是说,它和 Windows XP 的其余部分具有相同的外观,包括圆角窗口以及与标题栏类似的更具质感的图案背景。显示容器背景时,TaskSwitcher 使用了 uxtheme.h 中的很多新的主题 API,例如 OpenThemeData(英文)、CloseThemeData(英文)、GetThemeBackgroundRegion(英文)和 DrawThemeBackground(英文)。在本例中,我们把用于开始面板顶部的外观风格用作容器窗口的背景。

#include <uxtheme.h>
#include <tmschema.h>

// AltTab 列表容器窗口的对话框程序
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM, LPARAM lParam)
{
    static HTHEME htheme = NULL;

    switch (uMsg)
    {
        case WM_INITDIALOG:
        {
            htheme = OpenThemeData(hwnd, L"StartPanel");

            if (htheme)
            {
                // 获取要用于绘制容器窗口的
                // 背景区域部分并将其应用于
                // 对话框。

                HRGN hrgn = NULL;
                GetWindowRect(hwnd, &rc);
                OffsetRect(&rc, -rc.left, -rc.top);

                if (SUCCEEDED(GetThemeBackgroundRegion(htheme, NULL, 
                           SPP_USERPANE, 0, &rc, &hrgn)))
                {
                    SetWindowRgn(hwnd, hrgn, FALSE);
                }
            }

            break;
        }
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            if (hdc)
            {
                if (htheme)
                {
                    // 外观风格处于活动状态,使用外观
                    // 风格 API 进行绘制。

                    RECT rc;
                    GetWindowRect(hwnd, &rc);
                    OffsetRect(&rc, -rc.left, -rc.top);

                    DrawThemeBackground(htheme, hdc, SPP_USERPANE, 0, &rc, NULL);
                }
                else
                {
                    // 外观风格不处于活动状态,按传统
                    // 窗口样式进行绘制。
                }
            }
            EndPaint(hwnd, &ps);

            break;
        }
        case WM_THEMECHANGED:
        {
            // 外观风格已更改,关闭现有的 htheme 并尝试
            // 打开一个新的 htheme。
            if (htheme)
            {
                CloseThemeData(htheme);
            }
            htheme = OpenThemeData(hwnd, L"StartPanel");

            break;
        }
    }
}

图 3:TaskSwitcher AltTab 容器窗口

使用 Comctl32.dll 版本 6

Taskswitcher 利用了 comctl32.dll 版本 6 中的一些新功能。例如,图标列表使用 ListView 控件制作;容器的背景使用了匹配的背景水印,从而达到与窗口其余部分的自然融合。此外,API DrawShadowText 也是在 comctl32 v6 中找到的。

Comctl32 版本 6 是一个并行 DLL,即 comctl32.dll 版本 5 和版本 6 是同时安装在系统上的。默认情况下,当应用程序与 comctl32.lib 静态链接时,将使用版本 5。为了使应用程序能够使用版本 6,必须提供一个如下的应用程序声明文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
<assemblyIdentity 
version="1.0.0.0" 
processorArchitecture="X86" 
name="Microsoft.Shell.TaskSwitch " 
type="win32" 
/> 
<description>TaskSwitcher:AltTab 替代程序。</description> 
<dependency> 
<dependentAssembly> 
<assemblyIdentity 
type="win32" 
name="Microsoft.Windows.Common-Controls" 
version="6.0.0.0" 
processorArchitecture="X86" 
publicKeyToken="6595b64144ccf1df" 
language="*" 
/> 
</dependentAssembly> 
</dependency> 
</assembly> 

然后通过在 .rc 文件中指定以下行,将该声明文件编入应用程序的资源部分。

CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "TaskSwitch.exe.manifest" 

总结

Windows XP 提供了一个全新的用户界面,包括新的外观风格以及能够直观捕获窗口内容的能力。使用本文介绍的技术,开发人员可以利用外观风格 API 为其应用程序设计一个可以与 Windows XP 其余部分的外观相匹配的独特外观。使用 PrintWindow,开发人员可以制作指定窗口的快照并将其插入设备环境。

<!--- end main ---><!--- end --->
分享到:
评论

相关推荐

    C++ 使用PrintWindow实现窗口截图功能

    C++ 中使用 PrintWindow 实现窗口截图功能是通过使用 Windows API 的 PrintWindow 函数来实现的。在这个示例代码中,我们可以看到使用 PrintCaptureHelper 类来实现窗口截图功能。 首先,我们需要了解 PrintWindow ...

    Windows_API.rar_API.r_delphi windows api_vb windows api_windows

    总的来说,这个资源包为Delphi和VB开发者提供了一个全面的Windows API学习平台,通过深入学习和实践,开发者可以提升自己的编程技能,开发出更加高效、功能丰富的Windows应用程序。在学习过程中,建议结合具体的项目...

    python应用windows api对后台程序窗口及桌面截图并保存的方法和代码实现

    在本文中,我们将介绍使用 Python 应用 Windows API 对后台程序窗口及桌面截图并保存的方法和代码实现。 标题:Python 应用 Windows API 对后台程序窗口及桌面截图并保存的方法和代码实现 描述:本文将介绍使用 ...

    _WinAPI_PrintWindow_winapiprint_au3打印图片_au3_

    在Windows API中,`PrintWindow`函数是一个非常实用的工具,尤其对于自动化脚本和应用程序开发者来说。在本文中,我们将深入探讨`PrintWindow`函数的使用,以及如何结合AutoIt(AU3)语言实现屏幕截图和打印图片的...

    高级屏幕截图应用程序(酷)

    在这款屏幕截图应用程序中,C#的强大性能和灵活性得到了充分展现。它允许开发者构建用户友好的图形界面,同时提供高效的代码执行效率,使得应用程序运行流畅,响应快速。 屏幕捕捉是该程序的核心功能,它通过操作...

    vb 用PrintWindow函数后台截图或被遮住控件

    用PrintWindow函数快速截图并保存,可以截图后台或被遮住控件 最小化的话就只能截到一小块标行务栏标题一样了。 先打开一个记事本,输一些内容进去然后就可以开始截图了,软件会把记事本窗体与内容一起截下来

    vb屏幕捕获程序源码

    5. `XpStyles.res`: 可能是资源文件,用于应用Windows XP风格的外观到应用程序。 6. `MSSCCPRJ.SCC`: 这是版本控制系统的相关文件,通常与Visual SourceSafe(VSS)关联,用于管理源代码。 7. `Capture Genius v...

    一个VC写的屏幕截图程序源码

    2. **屏幕捕获函数**:在VC++中,捕获屏幕的函数可能使用Windows API的`BitBlt`或`PrintWindow`等函数。`BitBlt`用于从一个设备上下文到另一个设备上下文的位图复制,而`PrintWindow`可以直接从窗口获取位图,这对于...

    Windows Capture插件-Unity-Windows桌面实时展现-同步桌面

    这个插件能够轻松实现在Unity中展示实时Windows桌面。用法:直接将资源解压后放入项目的Assets文件夹即可。如果存在问题请更换Unity版本。具体用法请关注我后搜我的博文:【unity】如何用Unity获取Windows桌面

    WinAPI_Delphi 新编WinAPI参考大全 chm文件

    《WinAPI_Delphi 新编WinAPI参考大全》是一本专为Delphi开发者设计的权威指南,它详尽地介绍...通过阅读和实践书中的示例,你将能够更好地理解和掌握Delphi与WinAPI的结合使用,从而提升你的Windows应用程序开发能力。

    定时重启关机的小程序

    Windows系统中使用`shutdown.exe -s`命令,而Linux则使用`poweroff`命令。在设计程序时,也应考虑通知用户即将关机,以便他们能保存工作。 3. **截图功能**:截图功能通常涉及捕获屏幕图像并保存为文件。在Windows...

    C# 编写的一个简单易用的 Windows 截屏增强工具源码.zip

    在本项目中,我们讨论的是一个使用C#编程语言编写的Windows屏幕截图增强工具的源代码。这个工具不仅提供基本的屏幕捕捉功能,还...通过深入研究这个源代码,开发者可以提升对C#语言特性和Windows应用程序开发的理解。

    仿QQ,屏幕截图程序

    首先,屏幕截图的核心技术是Windows API(应用程序接口)中的`PrintWindow`函数。这个函数能够捕获窗口的内容并将其作为一个位图复制到内存中。在仿QQ屏幕截图程序中,开发者可能利用了这个API来获取当前活动窗口或...

    windows抓屏技术

    Windows 抓屏技术是指在 Windows 操作系统中捕捉桌面或某个窗口的内容的技术。该技术广泛应用于桌面共享、远程桌面、屏幕录制等领域。在 Windows 系统中,有多种不同的抓屏技术,包括 BitBlt、Mirror Driver、GDI ...

    类似QQ截图功能的小程序

    在这个案例中,"VC"标签意味着程序是用C++语言,借助Visual C++ IDE构建的,可能涉及到MFC(Microsoft Foundation Classes)库,这是一个用于构建Windows应用程序的C++类库。 【文件名称列表】: 1. ...

    抓取屏幕图像并在视图窗口中显示

    这个过程可以通过编程实现,以便在应用程序中动态展示屏幕内容。本篇文章将深入探讨如何实现“抓取屏幕图像并在视图窗口中显示”的技术。 首先,我们来理解“抓屏代码”的基本原理。在大多数编程语言中,都有相应的...

    自写截屏程序

    在Windows系统中,我们可以使用Windows API函数如`BitBlt`或`PrintWindow`来实现这一目标。在Linux系统中,可以利用X Window系统的`XShmGetImage`或`XGetImage`函数。在macOS中,可以使用Quartz框架进行截图。 接...

    VB截屏程序

    这通常是通过调用Windows API(应用程序编程接口)中的函数,如`BitBlt`或`PrintWindow`来实现的。这些函数可以获取屏幕或窗口的像素信息,并将其复制到内存中的位图。 2. **图像保存**:捕获到的屏幕图像会被保存...

    PB 截图 api

    在描述中提到的“pb8例子”,意味着这个API可能是在PowerBuilder 8版本中使用的一个实例。在PB8中,开发者可能通过调用特定的API函数来实现屏幕截图的功能。通常,这个过程包括选择要截取的窗口区域,捕获图像数据,...

Global site tag (gtag.js) - Google Analytics