VC2012 RTM released – linker minimum required version setting now supports XP

VC2012 RTM has been released, and my xpsupport version 1.10 (post Release Preview version) files available at

https://skydrive.live.com/?cid=1b361bf333e9ab82

are holding up well.  The main changes between Release Preview and RTM are that new calls to Vista only thread pooling functions have been added to the CRT (so I had to wrap them in 1.10), and the way that the ConCRT libraries are initialized had to be changed slightly to carefully set the internal cached OS version back to XP after hacking it temporarily to Vista.   So if you’ve already upgraded to 1.10, no changes are necessary if you just upgraded to RTM, otherwise upgrade your xpsupport version now!

And now some good news: in previous VC2012 betas/candidates, the minimum version you could set in your binary was 6.0 (Vista) which meant you had to use EDITBIN to change the version of your executable to hack it back to 5.1.

Now, The RTM linker supports setting SUBSYSTEM version to 5.1!  In fact you no longer need to fumble around with command line options. In the IDE you can just go to project properites, then linker settings – system, and set minimum required version to 5.01.  And once you do that it conveniently also sets OSVERSION for you to 5.1.

This was probably put in early to prepare for the eventual full support for XP targeting later this fall.  Of course, with this setting (5.1) specified in the linker you still cannot run an app created by VC2012 RTM in XP due to missing ordinals, but it saves a few steps when performing my VC2012 XP targeting instructions at

http://tedwvc.wordpress.com/2012/03/11/how-to-get-visual-c-2012-vc-11-beta-statically-linked-crt-and-mfc-applications-to-run-on-windows-xp/

Now the countdown begins for the eventual release of full XP targeting support by Microsoft, and these wrappers can then be finally put to rest.

How to get Visual C++ 2012 (VC 11 Beta) statically linked CRT and MFC applications to run on Windows XP

EDIT (April 14, 2013): If you’re having trouble with Microsoft’s XP support after installing Visual Studio 2012 Update 2 then please ignore this blog post! Read the new blog post instead.

EDIT (November 26, 2012): Microsoft has made their final release of Visual Studio 2012 Update 1 available which includes official XP targeting support!

EDIT (October 14, 2012): Microsoft has released their CTP of the XP targeting support, negating any further need for these wrappers.  Please use the official Microsoft solution from now on.

EDIT (June 20, 2012): Microsoft has announced XP targeting support will be added to Visual C++ 2012 in a post-RTM update.  Read the details here.  In the meantime you can use the below as a temporary workaround until the update has been released.

Source files and sample projects for this article located at: https://skydrive.live.com/?cid=1b361bf333e9ab82

Files last updated: 2012-07-10

XPSupport wrappers version 1.10

One of the major limitations of Visual C++ 2012 is that it does not create applications that can run on Windows XP.  As most of you already know, there is a connect item at Microsoft on this.  See: http://connect.microsoft.com/VisualStudio/feedback/details/690617

Note that the connect item was closed as “by design” and it was stated that only Vista SP2 and above is supported.  So this leaves out XP and Server 2003.

As you can see from the comments, many users simply will not adopt VC 11 because of its lack of XP targeting support.  Whether the Visual Studio 11 tools run on XP is a whole other story.  I don’t need the IDE to run on XP. What I need is the ability to use VC 11 (and all of its powerful new language features) AND still be able to target XP as a platform to deploy my apps to.

If you’re a long time reader of my blog, you know that I have written another article in the past on how to target Windows 2000 when using Visual Studio 2010.   In that article I explained that there is a simple trick that we can use to “wrap” missing API functions.  This involves making a small assembly language forwarding directive that calls our own C++ wrapper function.  If we use this trick we can substitute our own versions of any API symbol that is linked into our app, without causing any multiple symbol errors in the linker.  This means we do not have to use /FORCE:MULTIPLE.

To summarize, if we run dependency walker (available from www.dependencywalker.com) on a built executable that uses CRT and/or MFC 11 on Windows XP SP3, we’ll see a bunch of “red” icons beside the functions that are missing on XP (mostly in kernel32.dll). Our goal is to get rid of all of this red before it will run correctly on XP.

An aside: If it were truly a technical limitation to drop XP, then it would be impossible for us to “wrap” every instance of these functions without touching the original CRT and/or MFC static lib source code.  I’m about to show you a simple, elegant way to give your VC 11 apps the gift of XP support, while allowing the exact same binary to run on higher versions as well (e.g Vista, 7, Server 2008, etc)

There is another new roadblock that Microsoft has put in our way.  Previous to VC 11, we could override both the minimum operating system and subsystem version numbers using a linker command line option.  However in VC 11, they only allow specification of 6.0 (Vista) as a minimum.  That means there is NO way to write the necessary operating and subsystem versions to the built binary without a separate post-build tool.

Turns out that writing the operating system and subsystem version numbers can be acheived using EDITBIN.EXE (a tool that is included with VC11)  This means we can use this as post-build step just after linking occurs.

All that needs to be done is to run editbin.exe on the built executable itself, e.g.

EDITBIN.EXE testapp.exe /SUBSYSTEM:WINDOWS,5.01 /OSVERSION:5.1

It still throws a warning that the subsystem supplied is invalid but writes it anyway (unlike linking which refuses to write it when it’s invalid).

Note: if you’re trying these instructions with a console application, use

EDITBIN.EXE testapp.exe /SUBSYSTEM:CONSOLE,5.01 /OSVERSION:5.1

instead.

Notice that in the title of this blog post, I say “statically linked”.  There is good reason for that.  Microsoft no longer provides makefiles for their DLLs (since VC2010).  The last version to provide makefiles was VC2008.  That is unfortunate, as I could have provided a way to make dynamically linked apps run on XP as well.  But for now, we’ll have to do with a solution for statically linked apps only. I suggest you put pressure on Microsoft using the avenue of your choice to have them make available steps or makefiles that will allow us to rebuild the CRT and MFC DLLs.  If they agree, then I can provide a follow-up to this blog entry.

So, without further ado, here they are, two walkthroughs on how to create either a CRT or MFC statically linked app in Visual Studio 2012 that runs on Windows XP (resulting executable tested on a Windows XP SP3 machine that has been updated using Microsoft (Windows) Update with the various security fixes. This has not been tested on Windows XP x64 edition, and I don’t expect to be adding support for it as it’s a relatively underused operating system.

Simplified 4 step summary of solution:

(1) Add assembly language support to your existing project

(2) Add 4 files that I wrote that “wrap” the missing CRT and MFC functions (downloadable from my skydrive).  You only need 2 of these files if your app is not using MFC.

(3) Add a post-build event that runs EDITBIN.EXE to set the operating system and subsystem versions of your built app.

(4) Build your app, copy to XP and run it

That’s it. No complicated source code changes.  You simply need to add some wrapper code to your app and then use a tool to change a binary after it’s built.

In all cases, the wrapper code defers to the OS versions of the APIs (using GetProcAddress) when running on operating systems higher than XP/2003, and on XP/2003 uses either specific wrapper code (when needed) or appropriate return codes that allow the calling functions to continue.

Here’s a walkthrough that describes each of the above steps in detail (I’ve provided both CRT and MFC versions of the walkthrough, choose one or the other depending on whether your app uses MFC or not).

Grab the 3 zip files here first: https://skydrive.live.com/?cid=1b361bf333e9ab82

The first two zip files testapp.zip and testmfcapp.zip are complete examples of CRT and MFC apps respectively.  Both of them contain the custom build step with editbin.exe that I mentioned and the changes mentioned in the walkthrough already applied.   The third, xpsupport.zip contain the 4 files required (only need 2 files if CRT project) to add to an existing project that you may have (or use them with newly created projects when going through the walkthroughs below)

IMPORTANT NOTE: if you use these wrappers with your existing projects, you must change both your WINVER and _WIN32_WINNT to 0x0600 in your stdafx.h files.  Otherwise a lot of Vista and later specific structures and defines that I use will not compile correctly.  I may fix this in a future release.

CRT (Win32 or console app) version of walkthrough:

1) Launch Visual Studio 11 Beta (could be named Visual Studio 2012 if this article being read after the RTM was released)

2) Create a Win32 app (Win32 Project), or console app, call it testapp, keep all the defaults and click finish (note: if you decide to create a console app in this step, please add an include for “windows.h” to your generated project’s stdafx.h file)

3) Right click on the project in solution explorer (not the solution, but the project – usually the second line from the top in the solution explorer view) and choose “Build Customizations…” menu item.

4) Click the checkbox (on) beside “MASM (.targets,.props), and hit OK.

5) Right click on the project and choose “Properties” menu item to bring up project properties

6) choose “release” configuration

7) change this project to statically link to the CRT (change to Release version of project, then using project properties – configuration properties – C/C++ – code generation: change runtime library to multithreaded (instead of multithreaded DLL),

8) choose “debug” then do the same in Debug as in step 7 (except change to multi-threaded Debug)

9) Choose “all configurations”

10) Choose Configuration Properties – Build Events – Post Build Event

11) If your app is a Win32 app add the following two steps to the “Command Line” section of the Post Build Event:

ping 127.0.0.1 -n 3 -w 1000

editbin.exe "$(TargetPath)" /SUBSYSTEM:WINDOWS,5.01 /OSVERSION:5.1

otherwise, if your app is a console app, then add the following two steps instead  to the “Command Line” section of the Post Build Event:

ping 127.0.0.1 -n 3 -w 1000

editbin.exe "$(TargetPath)" /SUBSYSTEM:CONSOLE,5.01 /OSVERSION:5.1

12) Hit OK

13) Get the xpsupport.zip file from my skydrive and extract 2 of the 4 files (xpcrt.cpp, xpcrtwrap.asm ) to the folder where your source code is ( stdafx.cpp, etc), e.g. at

c:\users\<user>\Documents\Visual Studio 11\Projects\testapp\testapp

14) Right click on Source Files folder, and choose Add – Existing Item

15) add the 2 files that you copied in step 13: xpcrt.cpp and  xpcrtwrap.asm to your project

16) Build your application.  The 2 files you added in step 15 should have compiled correctly, and the version should have been set by editbin.exe.

17) head over to a Windows XP SP3 machine (or VM) and copy your debug/release folder over there, and try running the app. If all steps above were performed correctly, you now have your first Win32 CRT 2012 app running on Windows XP SP3.

MFC version of walkthrough:

1) Launch Visual Studio 11 Beta (or Visual Studio 2012 if this article being read after the RTM was released)

2) Create an MFC app, call it testmfcapp, keep all the defaults except choose to use MFC in a static library and hit Finish

3) Right click on the project in solution explorer (not the solution, but the project – usually the second line from the top in the solution explorer view) and choose “Build Customizations…” menu item.

4) Click the checkbox (on) beside “MASM (.targets,.props), and hit OK.

5) Right click on the project and choose “Properties” menu item to bring up project properties

6) Choose “all configurations”

7) Choose Configuration Properties – Build Events – Post Build Event

8) Add the following two steps to the “Command Line” section of the Post Build Event:

ping 127.0.0.1 -n 3 -w 1000

editbin.exe "$(TargetPath)" /SUBSYSTEM:WINDOWS,5.01 /OSVERSION:5.1

9) Hit OK

10) Get the xpsupport.zip file from my skydrive and extract the 4 files (xpcrt.cpp, xpcrtwrap.asm, xpmfc.cpp, and xpmfcwrap.asm ) to the folder where your source code is ( stdafx.cpp, etc), e.g. at

c:\users\<user>\Documents\Visual Studio 11\Projects\testmfcapp\testmfcapp

11) Right click on Source Files folder, and choose Add – Existing Item

12) add all 4 files that you copied in step 10: xpcrt.cpp, xpcrtwrap.asm, xpmfc.cpp, and xpmfcwrap.asm to your project

13) Build your application.  The 4 files you added in step 12 should have compiled correctly, and the version should have been set by editbin.exe.

14) head over to a Windows XP SP3 machine (or VM) and copy your debug/release folder over there, and try running the app. If all steps above were performed correctly, you now have your first MFC 2012 app running on Windows XP SP3.

Technical details of solution:

I’ve added comments to the code that describe the various wrapper functions that I had to write.  Several in particular I’d like to bring to your attention:

(1) Wrapper for GetTickCount64 uses some undocumented but well established Windows structures – please read over the definition of that function in the source code (xpcrt.cpp) for further comments about this.

(2) Wrapper for Locale name based APIs uses a DLL (nlsdl.dll) that ships with Internet Explorer 7 and above, or is available from Microsoft as a redistributable (see code comments for location and discussion of an alternative that does not require use of nlsdl.dll).  So basically if you can guarantee that IE7 or later or the nlsdl redist is installed on the XP SP3 machine, you can use this solution without any modifications whatsoever.

Troubleshooting:

If you get the error: “Not a valid win32 application”, then the editbin.exe step failed during your build.  Please check to make sure the two steps mentioned (the ping and the editbin.exe are separate lines in the command line – click “edit…” when adding them)

If you get any errors that entry points cannot be found, then you’ve probably forgotten a step above or have called a Vista function that I haven’t wrapped.  It’s also possible that you inadvertently added the asm files to your project before you did the “Build Customizations” step.  Build customizations must be done before ANY assembly files are added, or they won’t be compiled.

Comments/questions welcome.  And keep voting on the Microsoft connect item (link above) :)

XPSupport wrappers – Update History

1.00 2012-03-11 Initial Release

1.01 2012-03-13 added msvcp110 stuff (InitializeCriticalSectionEx, CreateSymbolicLink(A/W)

1.02 2012-03-15 added DwmExtendFrameIntoClientArea

1.03 2012-03-15 added fix for ConCRT runtime resource manager initialization (so std::thread can now be used)

1.04 2012-03-16 added PSGetPropertyDescriptionListFromString

1.05 2012-03-29 added wrapper for EnumSystemLocalesEx

website update: 2012-03-30 updated steps to use editbin.exe to set versions instead of a custom executable (to avoid needing a special EXE to set the version)

1.06 2012-05-05 added wrapper for GetLogicalProcessorInformation (for XP SP2 support – thanks Michael Chourdakis for this implementation)

1.07 2012-05-18 added wrapper for InitOnceExecuteOnce

1.08 2012-05-26 added x64 support – thanks to Antony Vennard (https://vennard.org.uk) for testing and correcting several errors in my initial test x64 release

1.09 2012-05-27 fixed non-Unicode (MBCS) builds and updated instructions to clarify usage with console apps (thanks to Latency and Antony for suggesting and helping with these fixes)

1.10 2012-07-10 added support for more recent builds of Visual Studio 2012 (CRT uses several API functions related to thread pooling) and updated source code to include a standard MIT license

New feature for MFC vNext: small statically linked dialog based and console apps

If you’ve read my blog in the past, you’ve noticed that I’ve written several articles relating to reducing the size of statically linked MFC apps. Ever since the feature pack classes were added to MFC (in 2008 SP1) there have been various regressions that caused even the simplest of MFC applications to be super-large when building a release version.

In vNext, Microsoft has attempted to address this issue by adding a new define: _AFX_NO_MFC_CONTROLS_IN_DIALOGS that basically says: I know that I will not have any of the “feature pack” controls in my app, so don’t link any code into the app that I’m not going to need.

From my testing so far, it only appears to work in console apps and MFC Dialog based apps. If you use it with a single document interface app, it will fail with a linker error.

The sizing results are dramatic, and I suggest you give the define a try if you are using MFC vNext and have a statically linked app.

Apps created with CRT and MFC vNext (11) cannot be used on Windows XP SP3

I filed a bug relating to no longer being able to target XP when creating a Visual C++ vNext app. I got a reply from a member of the Microsoft libraries team stating this is by design and only Vista and above or Windows Server 2008 SP2 and above can be targeted when creating a vNext application.

Please read the following and vote on it, add comments to it as well. If you believe that being able to create a single binary that can target XP and above, and still have access to the latest compilers, libraries, and headers that vNext provides (i.e. not have to use the “native multi-targeting” feature, then please see below:

http://connect.microsoft.com/VisualStudio/feedback/details/690617

MS11-025 has been reissued – all previously mentioned problems have been solved

Thank you to several readers who have alerted me to the fact that on June 15th, a whole new set of tools and redistributable patches for Visual C++ 2005, 2008, and 2010 have been released, fixing the problems that I blogged about a couple months ago. Please read MS11-025 where you’ll find links to the new tools updates and redistributables.

So any workarounds I’ve posted for the April 15th patches are no longer necessary once you update to the latest versions.

Relevant redist DLL versions:
VC2005 SP1 + KB2538218: 8.0.50727.6195
VC2008 SP1 + KB2538241: 9.0.30729.6161

As a bonus: the VC2008 SP1 static code bloat problem caused by the April 15th update has also been fixed by the above patch.

Of course, for VC2005 SP1 users, this blog post is still relevant if you want to control the version number in your manifest:

Avoiding problems with VC2005 SP1 Security update KB971090

Unexpected updates to developer tools caused by security updates – what do to about it?

The past week’s activity in security updates have generated a lot of new blog entries on this page. But does it have to be that way?

Martin Richter has written up a very good summary of why developers need the ability to freeze their environments (or at least be properly warned!!) when tools updates are released as important security updates. The main reason is because they need to target particular runtimes, and if they have to release hotfixes their manifests must match what is already out there. Another reason is that they simply cannot keep track of all the updates, and having your tools changed out from under you out of the blue can have major repercussions, especially if there are new bugs in those tools. It can cause massive numbers of hours of lost productivity in reconfiguring a whole organization’s developer machines.

I suggest you sign up for connect.microsoft.com (Visual Studio and .NET Framework) and read this (don’t forget to vote on it while you’re there):

Feature request: Always ask the developer before applying a security fix or service pack to Visual Studio that need changed the C++ runtime DLLs ATL/MFC/CRT

I definitely support having some better communication about the issues as well at the time they are released, like when KB971090 was released there was a video on channel 9 – see http://channel9.msdn.com/Blogs/Charles/Out-of-Band-Inside-the-ATL-Security-Update for the type of info that should be communicated.

Fixing problems with FindActCtxSectionString in MFC security updates

EDIT – June 18th, 2011 – the below blog entry is out of date – click here for up to date information.

In this blog entry I attempt to fix 3 of the problems associated with FindActCtxSectionString in a statically linked application (2005 and 2008). What I’m going to do is override the appcore.cpp that gets included in every static app with one that we’ll include in our app (again, like the last blog, no editing of the included file is necessary, which is a good thing because if there any updates you’ll get them by rebuilding)

1) Open up your stdafx.cpp file in your project (a statically linked MFC project)
2) Paste the following code after the include:

#undef FindActCtxSectionString
#define FindActCtxSectionString MyFindActCtxSectionString

#ifdef _UNICODE
#define _FINDACTCTXSECTIONSTRING "FindActCtxSectionStringW"
#else
#define _FINDACTCTXSECTIONSTRING "FindActCtxSectionStringA"
#endif

typedef BOOL (WINAPI * PFN_FINDAC)(DWORD dwFlags, const GUID *lpExtensionGuid,ULONG ulSectionId,LPCTSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData);

BOOL WINAPI MyFindActCtxSectionString(
     DWORD dwFlags,
     const GUID *lpExtensionGuid,
     ULONG ulSectionId,
     LPCTSTR lpStringToFind,
     PACTCTX_SECTION_KEYED_DATA ReturnedData)
{
	// Bug #1 - Windows 2000 
	PFN_FINDAC pfnFindActCtxSectionString =NULL;
	{
		HINSTANCE hKernel32 = GetModuleHandle(_T("kernel32.dll"));
		if (hKernel32 == NULL) 
		{
			return FALSE;
		}

		pfnFindActCtxSectionString = (PFN_FINDAC) GetProcAddress(hKernel32, _FINDACTCTXSECTIONSTRING);

		if (pfnFindActCtxSectionString == NULL) 
		{
			/* pre-fusion OS, so no more checking.*/
			return FALSE;
		}
	}
	
	ReturnedData->cbSize = sizeof(ACTCTX_SECTION_KEYED_DATA); // Bug #2 - missing cbSize initializer 
	return pfnFindActCtxSectionString(/* dwFlags */ 0,  // Bug #3 memory leak - pass in zero as return handle not freed
		lpExtensionGuid, ulSectionId, lpStringToFind, ReturnedData);
}

#include "..\src\mfc\appcore.cpp"

3) rebuild your app

Now, you get the following benefits
1) Successful running under Windows 2000
2) Properly initialized cbSize (see previous blog discussion)
3) Memory leak fix (passing in first parameter leaks a context handle)

Static MFC code bloat problem from VC2010 is now in VC2008 SP1+security fix

EDIT – June 18th, 2011 – the below blog entry is out of date – click here for up to date information.

Thanks to Owen Wengerd from Outside the Box for letting me know about this one – it’s a big regression. Turns out the the code bloat release size problem introduced in VC2010 with MFC statically linked applications is now a problem in VC2008 SP1, thanks to the new security updates of April 12th.

Problem:

It all started with MS11-025. This security update caused a multitude of problems with MFC, some of which are mentioned in previous posts. This particular one is specific to VC2008 SP1, it appears after installing KB2465361 and then rebuilding your existing statically linked MFC application(s).

What happened is that themehelper.cpp now uses the function AfxLoadSystemLibraryUsingFullPath which resides in the afxglobals.cpp file (as an inline function, no less!). As we know from previous experience in VC2010, if your app has to pull in afxglobals.obj for any reason, a cascade effect occurs and approximately 1.2 megs are added to your release EXE size. For example, using the Appwizard to generate a simple MDI app with a classic menu and toolbar, and no visual styles, and building a release is 553KB before the security update, and 1763KB after the security update.

Solution:

Luckily there’s a quick solution. Owen suggested one solution which was similar to my previous blog entry about reducing static size in VC2010, which is to copy and edit the afxglobals.cpp file. But it’s actually easier than that. When I originally wrote this blog entry, I made this suggestion: we’ll include themehelper.cpp in our stdafx.cpp file without copying it, just including it directly, and use some preprocessor magic to make it use our own local version of the AfxLoadSystemLibraryUsingFullPath function instead of the one in afxglobals.cpp. But Owen realized that all you really need is your own local copy of the AfxLoadSystemLibraryUsingFullPath function somewhere in your app, and even better, there won’t be any duplicate symbol errors! So the full solution is:

1) open up your stdafx.cpp from your project
2) paste the following code after the #include "stdafx.h"


// this is our own local copy of the AfxLoadSystemLibraryUsingFullPath function
HMODULE AfxLoadSystemLibraryUsingFullPath(const WCHAR *pszLibrary)
{
	WCHAR wszLoadPath[MAX_PATH+1];
	if (::GetSystemDirectoryW(wszLoadPath, _countof(wszLoadPath)) == 0)
	{
		return NULL;
	}

	if (wszLoadPath[wcslen(wszLoadPath)-1] != L'\\')
	{
		if (wcscat_s(wszLoadPath, _countof(wszLoadPath), L"\\") != 0)
		{
			return NULL;
		}
	}

	if (wcscat_s(wszLoadPath, _countof(wszLoadPath), pszLibrary) != 0)
	{
		return NULL;
	}

	return(::AfxCtxLoadLibraryW(wszLoadPath));
}

3) Rebuild your app, and voila, it’s all better now.

Problem with FindActCtxSectionString in MFC security updates on all platforms

Martin Richter has written a blog entry on a serious issue that was introduced when the MFC security updates were released on April 12. The culprit is, again, FindActCtxSectionString, but in this case it actually affects ALL platforms. Please read the following blog entry:

BUG: Black Patchday for all OS from XP and later 3. – MFC 8.0 (VC-2005) or MFC 9.0 (VC-2008) linked dynamically to the MFC may not find the MFC language DLLs after installation of the security packs dated April 12th 2011

New redists break all dynamically linked MFC 2005/2008 apps on Windows 2000

EDIT – June 18th, 2011 – the below blog entry is out of date – click here for up to date information.

Step by step instructions for Windows 2000 end users that want to get up and running quickly after having installed one or both of the invalid Visual C++ security redistributables on Windows 2000:

1) go to Control Panel – Add/Remove Programs, and uninstall the following (one or both may be installed)
a) Microsoft Visual C++ 2005 Redistributable – KB2467175
b) Microsoft Visual C++ 2008 Redistributable – KB2467174 – x86 9.0.30729.5570

Important: look for entries in the add/remove programs with the exact titles above, i.e including those KB article numbers in the title of the entry, as there may be similar looking ones in there (ignore those ones)

2) Find your “Windows” folder. Usually this is at c:\windows or c:\winnt . For the purposes of these instructions, I’ll assume it’s c:\windows (replace that below with your actual Windows folder)

3) Create a folder on your desktop named WORKDIR. You’ll use this later to hold all the DLLs you’ll be copying to your system32 folder.

4) Using Windows Explorer, go to c:\windows\winsxs. Hit the search button. For “Search for files or folders named”, type in 4053, and then hit ENTER. If nothing has been found type in 762 and hit ENTER.

5) There should be 5 folders that were found (as well as various other files that should be ignored, also, ignore any folders with amd64 at the beginning of their folder names). Note there may be some debug folders in here as well, brining the folder count up to 8.

Example of folder name: x86_Microsoft.VC80.MFC_1fc8b3b9a1e18e3b_8.0.50727.4053_x-ww_b77cec8e

6) For each of these 5 folders (or 8 if you have Debug some debug folders), do the following:
a) double click on the folder.
b) Edit – Select all (or CTRL+A)
c) Edit-Copy (or CTRL+C)
d) click on your desktop and open the WORKDIR folder you created above, and then hit Paste (or CTRL+V).
e) return to the Windows Explorer search window and click the “Back” button.

7) Repeat step (4) except search for 4148. If nothing found, search for 21022, then repeat steps 5 and 6.

8) Now your WORKDIR folder should be full of all the DLLs you will require to have copied to your C:\Windows\System32 folder. Open the WORKDIR folder on your desktop, and select all (CTRL+A) and then Edit-Copy (CTRL+C). Then navigate to your Windows\System32 folder and Paste (CTRL+V). If you receive any errors pasting (files in use) you may have to reboot and/or exclude the MSVCR* files when copying and pasting. At a minimum, you’ll need to copy at least the MFC related DLL files (files with MFC in their names)

9) Try running the problematic applications again, to make sure the problem has been fixed.

More background info:

Thanks to Martin Richter on letting me know about this one – the new VCRedists that were rolled out yesterday due to the multi-version security update breaks all dynamically linked MFC 8.0 and 9.0 (VC2005/VC2008) apps that have ever shipped and are deployed to Windows 2000. Any app that doesn’t have a local copy of MFC in their program folder is affected (due to DLL Hell in system32)

If you install them (do this on a test machine not a production machine!), run dependency walker on the updated mfc80.dll and mfc90.dll versions on Windows 2000 and see a new function being called that is not available under XP:

FindActCtxSectionStringA (or FindActCtxSectionStringW with the Unicode version)

These are the links to the broken redistributables:

VC2005

VC2008

A simple workaround under Windows 2000 is to copy the older versions of MFC80.DLL and MFC90.DLL (or their corresponding Unicode versions) to your program folder(s). Then your app will use those instead (remember Windows 2000 was a pre-SxS world).

To find these old DLLs is tricky – what would have been nice is that something like this would work:
(1) Uninstall redist update
(2) copy older versions from system32 to your program folder

but unfortunately, uninstalling it just leaves the new (broken ones) in system32. No way to retrieve the old ones. Or is there?????

Yes it turns out: Luckily (and luckily I remembered this from years ago), Windows 2000 still installs the DLLs to WinSxS. So the old ones are still there. So the workaround is to copy from the WinSxS folder the older version of MFC8 or 9 back to system32 or your program folder. But of course, this solution not benefitting from the security updates that are so important. So the best workaround is wait for a new version to be issued by Microsoft.

Special note for those that statically link their MFC apps: you will only be affected if you update your tools (i.e. KB2465367 for VS2005, or KB2465361 for VS2008, VS2003 may be affected as well but I don’t have time to check it – see KB2465373) and then recompile your application. Then your app will no longer run on Windows 2000. So beware of installing these tools updates if you plan on rebuilding your app and releasing it and expect it to work on Windows 2000.