A Simple Way to Enable a Windows XP Look and Feel for VC++ 6.0 MFC Applications
The main reason for writing this article is that Visual C++ 6.0 wizards-generated MFC applications don't use the XP look and feel controls if you run them under XP. If you are using Microsoft Visual C++.NET, that is not an issue. I had a goal to develop an application running under any Microsoft 32-bit OS and use the new UI look and feel if it runs under XP.
The solution is very simple. All you need to do is add a custom resource to the project and add a couple of lines to the InitInstance method of the CWinApp derived class.
1. Create a Manifest File
Microsoft has introduced a new type of resource called Manifest. Well, technically it's not a type of resource; it is just an XML file included to the app as a custom resource with ID=1, which describes the application and its dependencies. If an executable file contains this resource, Windows XP will identify it and force the application to use the specific versions of libraries. Our goal is to enforce usage of new Windows Common Controls library (version 6).
Here is an example of a simple manifest file that I've used to solve this task:
<?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.Windows.YourApplication"
type="win32"
/>
<description>YourApplication</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>
Create a file with its contents as shown above in the project resources folder (res by default). Replace YourApplication with an appropriate name. That should do it for our case. For further information about manifest files, see the MSDN for Visual Studio .NET.
2. Add a Resource to the .rc File
First, let's add two lines to the resource.h file. Just copy and paste the following:
#define IDR_MANIFEST 1 #define RT_MANIFEST 24
Now, open the application custom resource file. Usually, it's located in the res directory; the default extention is .rc2. Manually add the following line:
// Add manually edited resources here...
IDR_MANIFEST RT_MANIFEST MOVEABLE PURE
"res\\ApplicationManifestXMLFile"
Replace ApplicationManifestXMLFile with the actual file name.
3. Modify the InitInstance Method
It's really simple. Just copy and paste two calls at the beginning of the InitInstance method:
BOOL MoneyApp::InitInstance()
{
InitCommonControls(); // initialize common control library
CWinApp::InitInstance(); // call parent class method
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a
// shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC
// statically
#endif
// the rest of the code
}
4. Conclusion
This is it. No magic, but it works. You've got all the dialog controls, menus, and toolbars looking like their brothers and sisters in native XP applications. You can still develop under Windows 2000, but now I know that the UI of your applications will have a nice look under XP.
These screenshots illustrate how the same application looks under Windows 2000 and Windows XP:
![]() |
Running under Windows 2000 |
![]() |
Running under Windows XP before the changes |
![]() |
Running under Windows XP after the changes |
If you have any questions or ideas about this article, please drop me a couple of lines at alex@simanov.com.
Downloads
I've created a simple project (MFC dialog-based), demonstrating this technique.
Download demo project - 20 Kb.




Comments
Great job
Posted by softhor on 12/06/2006 05:57pmThanks a lot for your efforts. This is the simplest way to give old applications a new look.
ReplyNot working with...
Posted by Promotional Engine on 09/17/2006 11:18pmWhen using function 'CreateDialogIndirect' to show a dialogbox, the old-style buttons will be shown.
ReplyWay to Cool
Posted by Charlie Curtis on 04/18/2006 11:17amEasy to follow instruction and it works! Excellent article. Made my application look so much better... Thanks Charlie
ReplyCrashes with stingray grid controls
Posted by Dave McLelland on 08/03/2005 09:11amWith reference to Shail Srivastav's post, I have exactly the same problem, but don't know how to fix it. Can anyone enlighten me?
Replyworkaround for ownerdraw buttons
Posted by bob42 on 07/29/2005 03:11amIf you put an ownerdraw button onto a dialog, add that dialog to your window, register a callback with the dialog and dynamically update your button (add an image etc) it works in most cases. However, I still don't get the hang of all the custom window classes registered in this legacy code I'm working on. Sometimes adding dynamic buttons (without the above described dialog procedure) just works, sometimes it doesn't. Maybe someone knows a good primer on how low-level event handling works on Windows?
-
Replygot it, it's so pathetic
Posted by bob42 on 07/29/2005 04:43amIf you use two dialogs from your resources, and the two overlap, say a left dialog and a right dialog, and they are being created from left to right, then the left one may be below the right one. If you put a button on the right dialog though, on the very left, its event handler is never called. Sheesh!!
Replyworkaround for ownerdraw buttons
Posted by bob42 on 07/28/2005 11:37amIf you put an ownerdraw button onto a dialog, add that dialog to your window, register a callback with the dialog and dynamically update your button (add an image etc) it works in most cases. However, I still don't get the hang of all the custom window classes registered in this legacy code I'm working on. Sometimes adding dynamic buttons (without the above described dialog procedure) just works, sometimes it doesn't. Maybe someone knows a good primer on how low-level event handling works on Windows?
Replycrashes with stingray grid controls.
Posted by shail76 on 08/11/2004 02:41pmIts works great with MFC contols, but crashes with stingray grid controls. I am trying to fix this issue. If someone knows about fix, please let me know. My e-mail is shailsrivastav@hotmail.com Here is the stack and function _free_dbg_lk(void * 0x048edfb0, int 0x00000001) line 1066 + 60 bytes _free_dbg(void * 0x048edfb0, int 0x00000001) line 1001 + 13 bytes operator delete(void * 0x048edfb0) line 351 + 12 bytes CString::FreeData() line 146 + 15 bytes CString::~CString() line 213 CGXEditControl::CalcTextPosUnderPt(CPoint {x=0x0000027a y=0x00000040}) line 1698 + 33 bytes CGXEditControl::LButtonUp(unsigned int 0x00000000, CPoint {x=0x0000027a y=0x00000040}, unsigned int 0x00000051) line 628 + 19 bytes CGXGridCore::OnLButtonHitRowCol(unsigned long 0x00000001, unsigned long 0x00000006, unsigned long 0x00000001, unsigned long 0x00000006, CPoint {x=0x0000027a y=0x00000040}, unsigned int 0x00000000, unsigned short 0x0051) line 1985 CGXGridCore::DoLButtonUp(unsigned int 0x00000000, CPoint {x=0x0000027a y=0x00000040}) line 1080 CGXGridView::OnLButtonUp(unsigned int 0x00000000, CPoint {x=0x0000027a y=0x00000040}) line 450 + 30 bytes CWnd::OnWndMsg(unsigned int 0x00000202, unsigned int 0x00000000, long 0x0040027a, long * 0x0012fcac) line 1964 CWnd::WindowProc(unsigned int 0x00000202, unsigned int 0x00000000, long 0x0040027a) line 1585 + 30 bytes CGXGridView::WindowProc(unsigned int 0x00000202, unsigned int 0x00000000, long 0x0040027a) line 333 AfxCallWndProc(CWnd * 0x04754510 {CCSIPartTypeLibView hWnd=???}, HWND__ * 0x0028045c, unsigned int 0x00000202, unsigned int 0x00000000, long 0x0040027a) line 215 + 26 bytes AfxWndProc(HWND__ * 0x0028045c, unsigned int 0x00000202, unsigned int 0x00000000, long 0x0040027a) line 368 _CRTIMP void __cdecl _free_dbg( #endif /* _MT */ void * pUserData, int nBlockUse ) { _CrtMemBlockHeader * pHead; /* verify heap before freeing */ if (_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF) _ASSERTE(_CrtCheckMemory()); if (pUserData == NULL) return; /* forced failure */ if (!(*_pfnAllocHook)(_HOOK_FREE, pUserData, 0, nBlockUse, 0L, NULL, 0)) { _RPT0(_CRT_WARN, "Client hook free failure.\n"); return; } /* * If this ASSERT fails, a bad pointer has been passed in. It may be * totally bogus, or it may have been allocated from another heap. * The pointer MUST come from the 'local' heap. */ _ASSERTE(_CrtIsValidHeapPointer(pUserData)); /* get a pointer to memory block header */ pHead = pHdr(pUserData); /* verify block type */ _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)); /* if we didn't already check entire heap, at least check this object */ if (!(_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF)) { /* check no-mans-land gaps */ if (!CheckBytes(pHead->gap, _bNoMansLandFill, nNoMansLandSize)) _RPT3(_CRT_ERROR, "DAMAGE: before %hs block (#%d) at 0x%08X.\n", szBlockUseName[_BLOCK_TYPE(pHead->nBlockUse)], pHead->lRequest, (BYTE *) pbData(pHead)); if (!CheckBytes(pbData(pHead) + pHead->nDataSize, _bNoMansLandFill, nNoMansLandSize)) _RPT3(_CRT_ERROR, "DAMAGE: after %hs block (#%d) at 0x%08X.\n", szBlockUseName[_BLOCK_TYPE(pHead->nBlockUse)], pHead->lRequest, (BYTE *) pbData(pHead)); } -shail srivastav-
-
ReplyRE: crashes with stingray grid controls.
Posted by Dave McLelland on 07/30/2005 05:04amWhat was the problem with the stingray grid. Im modifying an app with Stingray grid 7.01 and have the same problem when I add a manifest.
ReplyI think the solution is easy
Posted by turkinz on 02/13/2005 04:45pmJust read the original docs here: Using XP Visual Styles 1 and this one here: Using XP VS -2 and you'll know why it crashes.
ReplySo Cool
Posted by Legacy on 01/24/2004 12:00amOriginally posted by: Ian
That really great work. It makes my application give fancy look. That's appriciable job. On the ohter hand I see one disadvantage as well. It makes my application slow in showing mutiples dialogs. It takes considerable time when I switch one panel to other with a lot of controls on them.
ReplyIt looks like it makes my application slow. Is there any remidy to this problem???
Fix for static wnds on tabs
Posted by Legacy on 01/12/2004 12:00amOriginally posted by: awinter
I like this code, it is really usefull. The only problem
I have encountered is the background of a static wnd when
it is placed on a tab wnd. The problem is caused by the
fact that the tab window has a gradient background, so
having a static wnd with a solid back color doesn't work.
The solution is simple, grab the region of the tab wnd
where the static wnd will be located and use this to paint
the background of the static wnd.
Enjoy!
ReplySimpler way of doing it without changing sourcecode !
Posted by Legacy on 12/10/2003 12:00amOriginally posted by: Geno Carman
ReplyLoading, Please Wait ...