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

将 Windows XP 视觉样式应用于应用程序

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.90/5 (18投票s)

2003年10月1日

CPOL

3分钟阅读

viewsIcon

174565

downloadIcon

2205

无需重建,即可将 Windows XP 可视化样式应用于应用程序。

引言

我一直想为 The Code Project 写一篇文章,因为它过去为我提供了很多非常有用的信息,并且回馈一些东西会很好。 主要问题是找到第一篇文章的合适主题,我希望我现在已经找到了。 所以开始了...

背景

Windows XP 带来了主题,这基本上只是所有常用控件(如按钮和滚动条)的新外观。 以下图片让您了解会发生什么。

Sample image

经典 Windows

Sample image

Windows XP 主题

这需要一段时间才能适应,尤其是如果您使用 Windows 已经很长时间了,但是如果您坚持使用一段时间,我相信您会像我一样喜欢它。 新主题的缺点是您需要告诉 Windows 您的应用程序应该使用新的样式常用控件。 据我所知,有两种方法可以实现这一点

  • 在与应用程序相同的目录中创建一个名为MyApp.exe.manifest的应用程序清单文件
  • 创建一个应用程序清单文件,并将其添加到内置于应用程序的资源列表中

这两种选择都不适合我们的软件包,因为它包含 500 多个函数,每个函数都是一个单独的 EXE 文件。 这意味着将生成数百个清单文件,并且如果选择第一种方法,则需要修改 CD 制作机制以将文件添加到安装 CD,并修改安装程序以安装它们。 这将是一个非常耗时的过程,而且如果清单文件格式在未来发生更改,也不会很灵活。

我提出的解决方案是在构建过程之外动态添加应用程序清单资源,这使我们能够将应用程序清单保留在一个源模块中,从而可以快速进行更改,以防格式发生更改。 本文解释了如何做到这一点。

使用代码

代码包含在一个函数中,如下所示,可以根据需要简单地放入任何程序中。 唯一的缺点是资源操作 API 函数仅在基于 NT 的操作系统下支持。 我已尝试尽可能完整地记录代码,但是如果缺少或不清楚的内容,请告诉我,我会对其进行更改。

//
// Add the XP style manifest to a specified applcation 
// 
DWORD AddManifest(const char *szFilespec, 
   const char *szProgName,const char *szProgDesc)
{
    // This is the formatting string used to create the manifest
    static LPSTR szFormat=    
     "<?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=\"%s\" "
            "type=\"win32\" />" 
        "<description>%s</description>"
        "<dependency>"
        "<dependentAssembly>"
            "<assemblyIdentity type=\"win32\" "
                "name=\"Microsoft.Windows.Common-Controls\" "
                "version=\"6.0.0.0\" " 
                "publicKeyToken=\"6595b64144ccf1df\" "
                "language=\"*\" " 
                "processorArchitecture=\"x86\"/>"
            "</dependentAssembly>"
            "</dependency>"
        "</assembly>";

    // Load the EXE so we can check if the resource already exists
    HMODULE hMod=LoadLibrary(szFilespec);
    if (NULL==hMod)
        return(GetLastError());
    
    // Attempt to find the manifest (resource type 24, id 1)
    HRSRC hRes=FindResource(hMod,MAKEINTRESOURCE(1),MAKEINTRESOURCE(24));

    // The EXE must be released before we can update the resources
    FreeLibrary(hMod);

    // If the manifest resource is not already present in the EXE
    if (NULL==hRes)
    {
        // Load the program ready for updating
        HANDLE hUpdate=BeginUpdateResource(szFilespec,FALSE);
        if (NULL==hUpdate)
            return(GetLastError());

        // Allocate a buffer to store the manifest string
        char *szManifest=new char[strlen(szFormat)+
                                  (szProgName ? strlen(szProgName) : 0)+
                                  (szProgDesc ? strlen(szProgDesc) : 0)+1];

        // Format the manifest to include the
        // specified program name and company name
        wsprintf(szManifest,szFormat,
           szProgName ? szProgName : "",szProgDesc ? szProgDesc : "");
    
        // Add the manifest resource to the list
        // of updates to be made (resource type 24, id 1)
        BOOL bUpdateSuccessful=UpdateResource( hUpdate,
                                MAKEINTRESOURCE(24),
                                MAKEINTRESOURCE(1),
                                MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_UK), 
                                szManifest,(DWORD)strlen(szManifest));
        // If the update was rejected
        if (!bUpdateSuccessful)
        {
            // Save the last error code
            DWORD dwLastError=GetLastError();

            // Release the memory allocated for the manifest string
            delete[] szManifest;

            // Abandon the resource changes and exit
            EndUpdateResource(hUpdate,TRUE);
            return(dwLastError);
        }

        // Release the memory allocated for the manifest string
        delete[] szManifest;

        // Apply the change to the specified EXE file
        if (!EndUpdateResource(hUpdate,FALSE))
            return(GetLastError());
    }

    // Resource modified successfully
    return(0);
}

关注点

我在开发此功能时遇到的最烦人的问题是,如果指定的文件以任何方式打开,则无法添加清单资源。 这包括使用LoadLibrary()来检查资源是否已经存在! 所有使用的函数都会返回成功值,并且在您尝试运行该应用程序之前,您完全不会意识到更新失败。

更多信息

我本文的主要信息来源可以在 MSDN 上找到这里。或者,Kluch 在本网站上发表了一篇出色的文章这里

结论

好了,这就是我的第一篇文章,已经完成并准备被 Code Project 社区挑选出来。 我只想快速“感谢”Kluch,他的文章给了我灵感和必要的信息来撰写本文。 我期待您的评论...

历史

2003 年 10 月 1 日 - 第一版

© . All rights reserved.