How to Consume DLLs in a WinRT/Metro Project

Yesterday, I published a small guide on how to consume DLLs in Visual C++ that explained how to best integrate a third-party library into a Visual C++ project. This is a follow-up article for Visual Studio 11 Beta users that contains the additional steps required to consume a normal (non WinRT Component) DLL in a WinRT/Metro project.

Assuming you have the DLL integrated into a WinRT application project as explained in my previous blog post, you will notice that when you try to run the application, there will be an error message stating that the Windows Metro style application could not be activated and the output window will report a missing dependency:

Screenshot of Visual Studio 11 reporting an activation error on a WinRT/Metro application

The reason for the error is that unlike desktop applications, a WinRT/Metro application is "deployed": packaged, sent to your installed app repository and remotely launched, not unlike what happens when you write a Windows Phone or Xbox application. The library DLL will simply not be part of the deployed files, even though it is in the project’s output directory.

Adding the DLL to Your Project

To solve this, you have to make the compiled DLL a part of the project. This creates a problem, because the compiled DLL will be in different directories, depending on whether you are compiling a Debug or a Release build and whether you are building for x86 or x64. Luckily, Visual C++ project files are based on MSBuild, an XML-based build scripting language.

Here’s what I did: first, I changed the output directories of my DLL project and my application to sane (and identical) values since the defaults appear rather arbitrary to me:

Screenshot showing where to find the output directory setting in a Visual Studio 11 project

Using the $(Configuration) variable, the properties can be identical for the Debug and Release configurations, but I still needed to enter them 3 times, once for each target platform supported by my project:

PlatformOutput DirectoryIntermediate Directory
Win32bin\x86\$(Configuration)obj\x86\$(Configuration)
x64bin\x64\$(Configuration)obj\x64\$(Configuration)
ARMbin\arm\$(Configuration)obj\arm\$(Configuration)

Next, I did a single build (any configuration is okay) and added the created DLL from my library project to my application project:

Screenshot of the context menu used to add existing items to a project in Visual Studio 11

I then closed Visual Studio and edited the .vcxproj file of my application project via Notepad to use MSBuild’s OutDir variable instead of the fixed path:

<ItemGroup>
  <CustomBuild Include="..\Library\$(OutDir)Library.dll">
  </CustomBuild>
</ItemGroup>

Yep, that works perfectly and Visual Studio also handles it nicely.

Deploying the DLL with Your Project

The next step is to configure the DLL to be deployed together with your project. This is rather easy: right-click the DLL, select "Properties" and set the file’s "Content" property to true:

Screenshot of the deployable content property for a file in a Visual Studio 11 project

If you’ve done everything as described, pressing F5 should now successfully execute the application and its library!

Optional: Remove .ref File

I could stop here, but now I have both a .ref and a .dll file for the library in my project. I can as well attach the custom build steps (see previous blog post) to the .dll file instead and remove the .ref

Here’s an example solution with containing an application and a DLL consumed by the application:

Possible Errors

If you are overly zealous in cleaning up build artifacts from your projects (I am!), you might run into the following error message:

Error    1    Error : DEP0600 : The following unexpected error occurred during deployment:
Illegal characters in path.
at System.IO.Path.CheckInvalidPathChars(String path, Boolean checkAdditional)
at System.IO.Path.Combine(String path1, String path2)
at Microsoft.VisualStudio.ImmersiveProjectServices.Shared.AppxLayoutManager.CheckPackageLayoutState(DeployPackageName deployPackageName, String location)
at Microsoft.VisualStudio.ImmersiveProjectServices.Shared.LocalDeployJob.GetLayoutState(DeployPackageName deployName, Boolean hasFrameworkDependencies)
at Microsoft.VisualStudio.ImmersiveProjectServices.Shared.RegisterAppxLayout.Start(Boolean forceNewLayout, Boolean forceRegistration, NetworkLoopbackState desiredNetworkLoopbackState, Boolean refreshLayoutOnly, String& packageMoniker, String& firstUserAppID, Exception& deployException)

If this happens, it means that your application is already registered in the WinRT/Metro app repository, but Visual Studio has lost the registration information (or something at least) which was stored in one of those intermediate directories.

To solve it, press Windows+Q (shows all installed applications), right-click on your application and pick "uninstall". After that, deployment should succeed again.

If the error persists, open your app’s Package.appxmanifest, navigate to the "Packaging" tab and enter a new Guid for the "Package Name". That way, your project gets a new identity and whatever is left in the WinRT/Metro app repository has no connection (and therefore won’t block) your app anymore.