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






3.90/5 (18投票s)
无需重建,即可将 Windows XP 可视化样式应用于应用程序。
引言
我一直想为 The Code Project 写一篇文章,因为它过去为我提供了很多非常有用的信息,并且回馈一些东西会很好。 主要问题是找到第一篇文章的合适主题,我希望我现在已经找到了。 所以开始了...
背景
Windows XP 带来了主题,这基本上只是所有常用控件(如按钮和滚动条)的新外观。 以下图片让您了解会发生什么。
经典 Windows
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 日 - 第一版