Windows Apps & Native WinRT Components Not Packaged as an SDK/Nuget Package

Something I came across this week that I didn’t really know how to deal with was the scenario where someone gives you a WinRT component written in C++ and you want to reference it from a .NET project but you don’t;

  1. have the source for it.
  2. have a Nuget package for it.
  3. have it nicely packaged as an extension SDK.

and if you just go ahead and reference the .winmd file from Visual studio then you can get into lots of errors around architecture mis-matches;

there was a mismatch between the processor architecture of the project being built ‘x86’ and the processor architecture….of the implementation file”

I didn’t know how best to deal with this so I played around with it a little, doing some web searching and building a bit more of a picture – feel free to disregard (and leave me a comment) if there’s a better way of doing this.

Starting with a Project Where I Have Source

If I start with a blank, C++ WinRT component project and just rename the component that the template gives me to make this amazing calculator component;

image

#pragma once

namespace NativeComponent
{
    public ref class Calculator sealed
    {
    public:
        Calculator();
		int Add(int x, int y);
		int Subtract(int x, int y);
		int Multiply(int x, int y);
		int Divide(int x, int y);
    };
}
// Class1.cpp
#include "pch.h"
#include "Calculator.h"

using namespace NativeComponent;
using namespace Platform;

Calculator::Calculator()
{
}
int Calculator::Add(int x, int y)
{
	return(x + y);
}
int Calculator::Subtract(int x, int y)
{
	return(x - y);
}
int Calculator::Multiply(int x, int y)
{
	return(x * y);
}
int Calculator::Divide(int x, int y)
{
	return(x / y);
}

No doubt there’s lots of ways to cause overflows and divide by zeroes there but, regardless, with that in place I can compile this up and the default project settings are going to build out 6 different outputs across debug/release configurations for ARM, x64 and Win32. All of those outputs are going to be called;

NativeComponent.dll

NativeComponent.winmd

and Visual Studio throws them into their own folders so that I don’t get them mixed up along with other supporting files like the .pdb files and the .pri resource files and so on.

If I then add a .NET project into the solution and make it so that it references the native component project;

image

Then I grow a couple of new target platforms for “AnyCPU” and “x86” and I hit the problem of having a .NET project which by default is going to try and target AnyCPU taking a dependency on a native project which, clearly, can’t target “AnyCPU”;

image

But that’s ok because I can switch my target configuration of the consuming .NET project to x86/x64/ARM and build out bits that target those platforms and it all works out fine and Visual Studio works out how to make sure that the right outputs from the native project are paired with the right outputs for the managed project for the right combinations of debug/release and x86/x64/ARM.

But…what happens if instead of a VC++ project, you just have the outputs in a set of folders? That is – I was looking at “an SDK” this week which was just some .winmd and .dll and .pri files.

To reproduce that, I can remove the VC++ project from my Visual Studio solution (which removes the reference) and then I put the VC++ outputs into a tree of folders like this;

image

and then I want to reference that component? On a 1:1 basis it kind of works in the sense that if I add a reference to one of the 6 .winmd files like the one from the x64/Debug folder then that works fine;

image

so long as I’m building out the x64 configuration of the code. If I’m building out anything else then I’m going to hit a mismatch;

image

and this single reference is not going to be able to cope with this.

I’m not 100% sure of what the “right” way is of going about this – the following 2 approaches work for me but there may well be another better/simpler way.

1 – Making a Nuget Package

What to do? One way is to create a Nuget package. This involves a bunch of steps and is written up here;

Packaging a Windows Store apps component with Nuget. Part 2

and is relatively convoluted for a native WinRT component but it seemed to be possible so I tried that out even though I. Am. Not. Very. Experienced. In. Making. Nuget. Packages.

Essentially, I copied that article above such that I ended up with the bits that I wanted packaged in a folder structure as below;

image

Each of those files is the output of a Release build and I didn’t attempt to package the .pdb files here. Each folder should speak for itself (i.e. ARM/x86/x64) except it might not be 100% obvious that what I have copied into the lib\Windows8 folder are all outputs of x86 builds which is what that original blog post suggested to do “so that the designer will work”.

I authored a .nuspec file which is as below;

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
    <metadata minClientVersion="2.5">
        <id>NativeComponent</id>
        <version>1.0.0</version>
        <authors>Mike Taulty</authors>
        <owners>Mike Taulty</owners>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>Dummy Native Calculator Component</description>
	<references>
		<reference file="NativeComponent.winmd"/>
	</references>
    </metadata>
</package>

and the .props file that you see above looks like this;

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

</Project>

and the .targets file looks like this;

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Target Name="PlatformCheck" BeforeTargets="InjectReference"
    Condition=" ( ('$(Platform)' != 'x86') AND ('$(Platform)' != 'ARM') AND  ('$(Platform)' != 'x64') )">
    <Error  Text="$(MSBuildThisFileName) does not work correctly on '$(Platform)' 
                     platform. You need to specify platform (x86 / x64 or ARM)." />
  </Target>
  
  <Target Name="InjectReference" BeforeTargets="ResolveAssemblyReferences">

    <ItemGroup Condition=" '$(Platform)' == 'x86' or '$(Platform)' == 'x64' or '$(Platform)' == 'ARM'">
      <Reference Include="NativeComponent">
        <HintPath>$(MSBuildThisFileDirectory)$(Platform)\NativeComponent.winmd</HintPath>
	<IsWinMDFile>true</IsWinMDFile>
	<Implementation>NativeComponent.dll</Implementation>
      </Reference>
    </ItemGroup>

  </Target>
</Project>

I’m not 100% sure that I need the IsWinMDFile and Implementation tags – you could experiment with removing them and see how that works out.

With those bits in place, I followed the blog post referenced to run Nuget.exe and package these bits up into a Nuget package as per below and, what the heck, I just ignored the warnings;

image

to get a Nuget package;

image

On my machine I have a local folder for Nuget packages as per the config dialog in Visual Studio below;

image

and so with this in place I can go and create a blank .NET Windows Store app project and add this Nuget package as a reference and then;

I spent about 20 minutes wondering why it didn’t work.

All seemed good. I had my reference in place;

image

I had some code that was using the library;

      Calculator c = new Calculator();
      int x = c.Add(1, 1);

this compiled for x86, x64 and ARM. But every time I tried to debug the project I was getting a FileNotFoundException at the point where the runtime tried to load up my NativeComponent.dll.

I spent quite a while on this before realising that it wasn’t the DLL itself that the runtime was struggling with but rather the old (obvious once you realise it having done it many, many times before) C++ runtime that it had a dependency on.

So, a quick reference to;

image

image

and life’s good or, at least seemed to be good on x86 and x64.

However, it’d be “nice” if the consumer of the package didn’t have to manually add this additional reference and if the package itself carried the details of the dependency.

Based on the “long discussion” up at  http://nuget.codeplex.com/discussions/396720 this sort of idea has been going around for a long time and I think that the way I’d need to do it is by altering the .props file that is part of my Nuget package. I could add something like this to it;

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>
    <SDKReference Include="Microsoft.VCLibs, Version=12.0">
      <Name>Microsoft Visual C++ 2013 Runtime Package for Windows</Name>
    </SDKReference>
  </ItemGroup>

</Project>

which seemed to work out a little bit better although I’m not sure whether the user has to close/open the project to get that additional reference picked up before building.

Given that the C++ runtime bits ship as an extension SDK, that prompted me to think about whether I could dress up my native component as one of those rather than a Nuget package…

2 – Making an Extension SDK

I. Know. Very. Little. About. Making. Extension. SDKs.

However, there’s a great guide to doing this up on Oren’s site here;

http://blog.novotny.org/2012/03/24/how-to-use-extension-sdks-per-project/

and that can be mixed with the write-up here on Code Project about how to use Visual Studio to make an extension SDK;

http://www.codeproject.com/Articles/521101/Deploying-a-Windows-Runtime-Component-Project-as-a

and I also found this discussion;

http://social.msdn.microsoft.com/Forums/windowsapps/en-US/52241956-1d39-4a1b-ba47-9d25d40f4d2f/how-to-distribute-native-and-managed-libraries-for-metro-apps?forum=windowsstore

and this reference;

http://msdn.microsoft.com/en-us/library/hh768146(v=vs.110).aspx#ExtensionSDKs

pretty useful too and this one helped massively as well;

http://www.sharpgis.net/2014/01/default.aspx

In the end, I dressed up the pieces of my native component’s outputs into a tree that looked like this;

image

with everything there being fairly naturally named and the SDKManifest.xml file looking as;

<?xml version="1.0" encoding="utf-8" ?>
<FileList
  DisplayName="Native Component"
Identity="NativeComponent, Version=1.0.0.0"
  ProductFamilyName="NativeComponent"
  MinVSVersion="12.0"
  CopyRedistToSubDirectory="."
  AppliesTo="WindowsAppContainer"
	DependsOn="Microsoft.VCLibs, version=12.0"
  SupportedArchitectures="x86;x64;ARM">
    <File Reference="NativeComponent.winmd" Implementation="NativeComponent.dll" />
</FileList>

and as per the previous article that I linked to it’s possible to get the system to look for extension SDKs in a number of different ways ( by setting a registry key, by changing a property in a project file ) but the way that I did this here was by simply having that NativeComponent folder that I’ve displayed the sub-tree for in the picture above sitting in the folder;

c:\users\mtaulty\appdata\local\Microsoft SDKs\Windows\v8.1\ExtensionSDKs\

and then I can make a new .NET project inside of Visual Studio and simply pick up this set of files as though it was a real, fully-fledged extension SDK that I had installed via a .vsix installer;

image

and then that seems to work out fine (at least in trying this out on x86, x64 platforms – I didn’t grab an ARM box and try it out).

Feel free to let me know if there’s a much better way of handling this situation and I’ll update the post but at least I have this written down so that the next time I get an unpackaged, native, WinRT component in binary form I’ll have something to refer back to with respect to how best to deal with it Smile