Visual C++ woes
It seems that with every new version of Visual Studio, Microsoft does something to alienate its users in regard to the C runtime, compiler and/or linker.
Back in the days of Visual Studio 6.0 (still, in my opinion, the best version to have ever existed, despite its age1), things were simple. There were no useless compiler flags to disable in every project, and the C runtime library was MSVCRT.DLL, which was distributed with the operating system. Actually, this is not fully the case, but MSVCRT.DLL has always been there due to the strong reliance of operating system components on it. It was therefore very simple to create small applications and to distribute them.
Then came Visual Studio 7.0, a.k.a. Visual Studio .NET 2002. Suddenly, someone somewhere decided that MSVCRT.DLL belonged “to the operating system” and not to Visual C++, and that therefore, its C runtime should now reside in a new, separate, redistributable DLL, MSVCR70.DLL. So suddenly, there was no real incentive to compile with /MD, as it would create the need to distribute a ~330k DLL along with the application. Personally, I would have remained with Visual Studio 6.0, but in the latest Platform SDK, which at the time was the then-new Windows XP SP2 Platform SDK, suddenly the format of the .lib files was just slightly incompatible with the aging linker.
I think it was in Visual Studio 7.1, which, by the way, I have never used personally, that the damned /GS compiler flag was introduced. What a better way to inflate code size uselessly than to add a prolog and epilog in every function that checks for a “security cookie”? Personally, I never allocate buffers and strings on the stack anyway, and when I do, I very strictly validate their length, so the protection offered by this flag is quite nil to me.
Then, in Visual Studio 8.0 (2005), somebody sure got angered at all the developers that were copying MSVCR7x.DLL around freely, so it was spoken: “From now on, the C runtime will only be installed by our own installer”. So, to install MSVCR80.DLL on a system, it’s not as simple anymore as just including the file in your installer and dumping it in the application’s directory during installation, you have to have a freaking manifest to even be able to load it! And of course, since this uses Fusion, the files need to be installed into specific subdirectories of the WinSxS directory, and therefore, the only “installer” qualified to do it correctly is the Visual C++ 2005 Reditributable Package, which weighs a whopping 2.6 MB! Quite a lot for what would have been an application of a few hundred kilobytes, now isn’t it? And to make sure you don’t ever try to bypass this “rule” and copy it in the application’s directory, the DLL does a check at startup to see if it was loaded “correctly”, and, if not, refuses to load.
Now, it isn’t that bad, I found a workaround to that (which I will explain in a future post), so I got used to that version and grew to like it.
I then recently got Visual Studio 9.0 (2008) and installed it. Not that it was really useful, since I already had the Windows Vista (February CTP) SDK installed over my Visual Studio 2005 installation, but I installed it just to be using the latest version. Actually, it’s not so bad, it’s even an improvement over the previous version. The /DYNAMICBASE and /NXCOMPAT flags are enabled by default (unless you migrate your project from Visual Studio 2005), and the operating system and subsystem version number in the PE headers were finally bumped to being set to 5.0 by default. That last point is also the frustrating point though. It was probably done that way because version 9.0 of the C runtime wouldn’t run correctly on anything lower than 5.0 anyway, but if you are not using the C runtime at all, there is no reason to set them to 5.0, other than artificially restricting the versions of Windows your program can run on. So, you might say, “let’s just tell the linker to set them back to 4.0 then”. Except, when you try to do that, you get this lovely little error:
LINK : warning LNK4010: invalid subsystem version number 4.0; default subsystem version assumed
Yes, you guessed right. The linker won’t let you set 4.0 as the subsystem version number. It looks quite like an useless restriction put there just to annoy some of us who still support, or just want to code for Windows 9x/NT4.
But as always, something like that isn’t enough to stop me, I created my own workaround:
The fact that an executable linked with Visual Studio 2008, but not using its C runtime, runs fine on Windows NT 4.0 afterwards proves how much of an artificial restriction that is.
The tool is up for download here.
- It’s not so bad once you install WndTabs and work around the few bugs in the resouce editor.

July 3rd, 2008 at 22:40
I had the same problem with /SUBSYSTEM. Tried to run one of my apps on NT4 and got something like “This is not a win exe”. Dumped the PE header with one of my PE utils and saw 5.0. Tried to change it back with /SUBSYSTEM but of course that !@#$ won’t let me. I hate tools that think they know better than yourself.
July 23rd, 2008 at 21:19
Patcher doesn’t seem to work on DLLs…”Failed to open … (32)” error.
July 23rd, 2008 at 21:23
Thanks. I will look into that.
July 28th, 2008 at 1:43
It works fine with DLLs, error 32 is “The process cannot access the file because it is being used by another process.”, therefore the problem is on your side.
December 7th, 2008 at 0:20
BTW, compare VC 6 to VC.NET with VB 6 to VB.NET.