We just ported the entire application codebase for one of our clients from Visual Studio 2005 to Visual Studio 2008. While working on the codebase we also decided to deploy the code on Windows 7.
Many of our managed applications are actually a composite of C# assemblies, managed C++ assemblies and InProc COM components. We’ve spent many man hours addressing the precarious marriage between the managed and unmanaged world.
While unit testing our work, we ran into a peculiar problem. When we tried to run one of our unmanaged applications, the following message box was displayed:
A closer look in the event viewer revealed the following:
That’s odd… until now we’ve never had to worry about managed applications requiring manifest files for side by side issues.
Managed C++ Assemblies
After pondering what we saw, it occurred to me that the incorporation of managed C++ assemblies was the most likely cause of the incompatibility. In the past looking at the About box in the version of the Visual Studio IDE used to build the target binaries was sufficient to determine the runtime version of the C/C++ assemblies. I clicked on the About box and made a note of the version of the runtime DLLs for this instance of the IDE.
The next step then is to add a manifest file to the target executable and set the version to the number in the About box. The resulting file looks something like this:
I compiled and ran the application… no dice.
It occurred to me that maybe we need to ensure that the managed C++ assemblies are binding to the correct resource versions for the runtime DLLs.
Managed C++ Manifest Support
The best way to ensure that the managed C++ assemblies bind to the correct runtime versions is to specify those version directives as linker directives. To do this, we create a new header file whose sole purpose is to emit the proper linker directives in a hands off fashion as follows:
I included this header in stdafx.h and proceeded to rebuild the DLL. The output I got was puzzling, to say the least…
Wait a minute… the IDE is set to 9.0.30729.1, yet the version the compiler sees is 9.0.21022.8. What is going on?
After digging around on the internet, I find that adding the following directive to the stdafx.h file should force the version to be the most current.
#define _BIND_TO_CURRENT_VCLIBS_VERSION 1
I add this and recompiled. Now the output is producing even stranger results:
What?
Alright, if that’s the version that’s current then we’ll go with that. I recompile the application and run only to be faced with:
Clearly something is amiss…
New Windows 7 Debugging Tools to the Rescue
Windows 7 comes with kernel support for enhanced deep dive tracing and logging of any event you can possibly imagine. This means developers can now trap metrics at a level far deeper than ever before possible, and with OS support that does not require code change.
Since we are facing a Side by Side issue, I chose to use sxstrace. Setting up the trace tool is rather straight forward. To start the trace, I ran the following command in a separate DOS box:
I then ran the application directly using the Windows explorer tool. One I got past the message box telling me I couldn’t run the application, I went back to the DOS box and hit <ENTER> to stop the trace.
The next step is to parse the .etl file to produce human readable text. I ran the following command in the DOS box:
The resulting file told the tale:
Error in the XML configuration file? The IDE clearly shows that the app.config file parses fine and is not in error. A look at line 1 shows the standard XML header.
What is going on?
A Sad Tale of XML Standards
The answer was staring me right in the face. Let me explain.
In prior versions of the Visual Studio IDE going back to 2002, the app.config file is produced as straight XML. The encoding specified is the code page for the target language supported. Since that time the standards committee has adopted the specification of using UTF-8 or UTF-16. On further examination, there are non-printable bytes that precede the first text character know as Byte Order Mark (BOM). This tells the XML parser what type of character set to expect before it begins parsing that text.
The byte order mark (BOM) is a Unicode character used to signal the endianness (byte order) of a text file or stream. Its code point is U+FEFF. BOM use is optional, and, if used, should appear at the start of the text stream. Beyond its specific use as a byte-order indicator, the BOM character may also indicate which of the several Unicode representations the text is encoded in.
Apparently, there are several different parse engines that parse the app.config file. The parser that reads the app.config for key-value pairs, etc understands the old VS2005 format. The manifest parser, however, chokes on the old format, and stopped on the keywords encoding="Windows-1252". The final piece of the puzzle fell into place when we changed that to the new standard:
encoding="utf-8"
But that’s only one part of the solution. To add the correct BOM we actually had to regenerate the app.config file in the VS2008 IDE. Once this last step was completed, the application ran fine.