The Visual Studio hosting process and 64-bit Windows

I’ve recently started working with Outlook Redemption, an excellent alternative to direct MAPI calls. Some of the other devs on my team wrote some libraries that use it, complete with unit tests. All the code and unit tests run fine on my machine (VS2008, 64-bit Windows).

                     /"\
                    |\./|
                    |   |
                    |   |
                    |>~<|
                    |   |
                 /'\|   |/'\..
             /~\|   |   |   | \
            |   =[@]=   |   |  \
            |   |   |   |   |   \
            | ~   ~   ~   ~ |`   )
            |                   /
             \                 /
              \               /
               \    _____    /
                |--//''`\--|
                | (( +==)) |
                |--\_|_//--|

In order to illustrate some functionality, I needed to write a simple console application that used the code that these other devs wrote, so I referenced it and tried it… and was given an exception (the computer version of the middle finger):

Unhandled Exception: System.Runtime.InteropServices.COMException (0x80040154): Retrieving the COM class factory for component with CLSID {29AB7A12-B531-450E-8F7A-EA94C2F3C05F} failed due to the following error: 80040154.

My first instinct was to search through the registry for the CLSID. Sure enough, it was there, and everything looked right. It has to be — otherwise, the unit tests (which use the exact same code) wouldn’t work.

The next thing I tried was unregistering and re-registering Redemption.dll (using regsvr32). No luck; unit tests work, console app fails.

Reboot? No luck; unit tests work, console app fails.

I did some reading, and apparently MSTest runs as a 32-bit application (though it can be run as 64-bit). I tried forcing Visual Studio to compile in x86? No luck; unit tests work, console app fails. Forcing Visual Studio to compile in x64 didn’t help either.

More reading, and I started to understand more about what the “Any CPU” platform compilation means, and the trials and tribulations of programming for 64-bit Windows. Now I am smarter, but I still can’t get my damn simple console application to work!

Seemingly out of options, I found myself staring at the Debug output directory, and noticed something:

SimplePstExtraction.exe
SimplePstExtraction.vshost.exe

I went ahead and turned off the Visual Studio hosting process, and viola! Everything works fine. I don’t know why, exactly (though I’m sure it’s related to the difference between 32- and 64-bit processes), but it fixed my issue, so if you have the same problem, hopefully it’ll fix yours.

MSTest, DeploymentItem, and the frustrating RelativePathRoot setting

MSTest, Microsoft’s unit-testing framework, has the ability to deploy files to a predefined test directory via the [DeploymentItem] attribute. The documentation, however, includes this vague reference:

  • [DeploymentItem("file1.xml")] Deploys an item named file1.xml located at the RelativeRootPath. The file is deployed to the deployment root directory.
  • [DeploymentItem("file2.xml", "DataFiles")] Deploys an item named file2.xml located at the RelativeRootPath. The file is deployed to the DataFiles subdirectory of the deployment root directory.

Sounds good, but what is RelativePathRoot? It wasn’t easy to find out, but eventually I came across a post on the MSDN forums, which stated:

… it is simply the directory of the solution containing your test project.

Hmm… This is great, so long as your test project only exists in one solution — or, if in multiple solutions, all solutions are in the same folder. Unfortunately for me (and likely many others), this isn’t the case.

How can we handle situations where our test projects have deployment items, but the test projects are included in multiple solutions in different folders?

The messy but effective solution is to have more than one [DeploymentItem] attributes for each deployment item, each having a path that is relative from the solution directory. Fortunately, if the source file in a [DeploymentItem] attribute doesn’t exist, the test doesn’t fail – otherwise this workaround wouldn’t work.

In other words, if you are starting with this:

[TestMethod]
[DeploymentItem("TestFiles\MyFile.txt")]
public void MyTest() { }

You would modify it like this:

[TestMethod]
[DeploymentItem("TestFiles\MyFile.txt")]
[DeploymentItem("path_from_other_solution\TestFiles\MyFile.txt")]
public void MyTest() { }

Replace “path_from_other_solution” with the path from your alternate solution to the solution folder for the test project.

Not pretty, but it works.