Introduction
I've wanted to write an article for The Code Project as it's provided me with some very useful information in the past and it would be nice to give something back. The main problem was finding an appropriate topic for a first article, which I hope I've now found. So here goes...
Background
With Windows XP came themes, which is basically just a new look for all the common controls such as buttons and scroll bars. The following images give you an idea of what to expect.
Classic Windows
Windows XP Themes
This takes a bit of getting used to, especially if you've been using Windows for a long time, but if you stick with it for a while I'm sure you will learn to like it as I have. The downside to the new themes is that you need to tell Windows that your application should make use of the new style common controls. As far as I'm aware there are two ways of achieving this:
- Create an application manifest file named MyApp.exe.manifest in the same directory as the application
- Create an application manifest file and add it to the list of resources built into the application
Neither option was appropriate for our software package as it contains over 500 functions, each being a separate EXE file. This would have meant generating several hundred manifest files and, if the first method was selected, modifying the CD production mechanism to add the files to the installation CD and modifying the setup program to install them. This would have been a very time consuming process and also not very flexible should the manifest file format change in the future.
The solution I came up with was to dynamically add the application manifest resource outside of the build procedure which gives us the advantage of keeping the application manifest in one source module allowing changes to be made quickly should the format change. This article explains how to do it.
Using the code
The code is contained within one function, shown below, that can be simply dropped into any program as required. The only drawback is that the resource manipulation API functions are only supported under NT based operating systems. I've tried to document the code as fully as possible but if there is anything missing or unclear, please let me know and I will change it.
DWORD AddManifest(const char *szFilespec,
const char *szProgName,const char *szProgDesc)
{
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>";
HMODULE hMod=LoadLibrary(szFilespec);
if (NULL==hMod)
return(GetLastError());
HRSRC hRes=FindResource(hMod,MAKEINTRESOURCE(1),MAKEINTRESOURCE(24));
FreeLibrary(hMod);
if (NULL==hRes)
{
HANDLE hUpdate=BeginUpdateResource(szFilespec,FALSE);
if (NULL==hUpdate)
return(GetLastError());
char *szManifest=new char[strlen(szFormat)+
(szProgName ? strlen(szProgName) : 0)+
(szProgDesc ? strlen(szProgDesc) : 0)+1];
wsprintf(szManifest,szFormat,
szProgName ? szProgName : "",szProgDesc ? szProgDesc : "");
BOOL bUpdateSuccessful=UpdateResource( hUpdate,
MAKEINTRESOURCE(24),
MAKEINTRESOURCE(1),
MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_UK),
szManifest,(DWORD)strlen(szManifest));
if (!bUpdateSuccessful)
{
DWORD dwLastError=GetLastError();
delete[] szManifest;
EndUpdateResource(hUpdate,TRUE);
return(dwLastError);
}
delete[] szManifest;
if (!EndUpdateResource(hUpdate,FALSE))
return(GetLastError());
}
return(0);
}
Points of interest
The most annoying problem I encountered while developing this function is that the manifest resource cannot be added if the specified file is open in any way. This includes the use of LoadLibrary()
to check if the resource already exists! All the functions used return success values and you will be totally unaware that the update has failed until you try to run the application.
More information
My main source of information for this article can be found on MSDN here. Alternatively there is an excellent article by Kluch on this site here.
Conclusion
Well that's it, my first article written and ready to be picked apart by the Code Project community. I'd just like to say a quick "thank you" to Kluch whose article gave me both the inspiration and information necessary to write this article. I await your comments...
History
01-10-2003 - First edition