欢迎光临
我们一直在努力

在 Windows 应用程序中使用 Windows XP 的外观风格和 PrintWindow(转)-.NET教程,Windows开发

建站超值云服务器,限时71元/月

注意:此示例仅适用于运行 windows xp 的计算机。打开示例并打开两个或多个应用程序窗口之后,请使用 alttab 功能键来运行 taskswitcher 应用程序。
摘要:本文介绍了一种增强的 alttab 应用程序 taskswitcher,并以此为框架演示了在 windows 应用程序中使用 windows xp 新的外观风格和 printwindow 的方法。

目录
简介
taskswitcher 应用程序
截取键盘输入
枚举顶层应用程序窗口
显示顶层应用程序窗口
使用 comctl32.dll 版本 6
总结
简介
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,开发人员可以制作指定窗口的快照并将其插入设备环境。

 

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 在 Windows 应用程序中使用 Windows XP 的外观风格和 PrintWindow(转)-.NET教程,Windows开发
分享到: 更多 (0)

相关推荐

  • 暂无文章