I'm trying to use the Windows 10 IoT Core C++ Background Application (based on the MSFT IoT templates).
My scenario involves creating a native (C++) Background Application that leverages an existing managed (C#) Runtime Component. I can create such a solution in Visual Studio and it compiles and deploys to an IoT device just fine.
However, when I run the app, I see runtime exceptions like this anytime the managed component is used:
Exception thrown at 0x76C92052 in backgroundTaskHost.exe: Microsoft C++
exception: Platform::ClassNotRegisteredException ^ at memory location
0x02B0F4A8. HRESULT:0x80040154 Class not registered
WinRT information: Class not registered
Stack trace:
[External Code]
backgroundapplicationcpp.dll!BackgroundApplicationCpp::StartupTask::
[Windows::ApplicationModel::Background::IBackgroundTask]::Run
(Windows::ApplicationModel::Background::IBackgroundTaskInstance ^
taskInstance) Line 13
Part of the promise of Windows Runtime is the interop of the languages (C++, C#, JS, VB) ... this scenario works just fine with a standard UWP app in place of an IoT Background Application.
How can this scenario work for Background Applications???
The part of the Visual Studio targets system that handles Background Applications is treating every library in the project as though it were the same language (C++) as the Background Application.
In this case, the managed Runtime Component is being treated like a C++ component. Because of this, the .NET libraries aren't being included in the deployment.
The next version of Visual Studio should contain a fix for this, but until then, I added this to my Background Application's vcxproj:
<!-- Workaround for bug in MSBuild regarding Native Background Applications referencing Managed Conponents -->
<PropertyGroup>
<CopyNuGetImplementations>true</CopyNuGetImplementations>
<NuGetRuntimeIdentifier>win10-$(PlatformTarget.ToLower())</NuGetRuntimeIdentifier>
</PropertyGroup>
<Target Name="_LocalResolvePrimaryProjectWinmdFiles" BeforeTargets="BeforeGenerateAppxManifest" AfterTargets="_ResolvePrimaryProjectWinmdFiles" Condition="'$(OutputType)' != 'exe' and '$(AppxPackage)' == 'true' AND '$(ContainsStartupTask)' == 'true'">
<ItemGroup>
<_AppxWinmdFilesToHarvest Remove="@(_AppxWinmdFilesToHarvest)" />
<_AppxWinmdFilesToHarvest Include="@(PackagingOutputs)" Condition="'%(PackagingOutputs.Extension)' == '.winmd' and '%(PackagingOutputs.ProjectName)' == '$(ProjectName)' and '%(PackagingOutputs.ResolvedFrom)' != 'GetSDKReferenceFiles'">
<!-- This covers the Managed Background Application winmd which does NOT have a WinMDFileType value set -->
<ImageRuntime Condition="'$(PrimaryProjectWinmdImageRuntimeOverride)' == ''">WindowsRuntime 1.4;CLR v4.0.30319</ImageRuntime>
<!-- This covers the C++ Background Application winmd which does NOT have a WinMDFileType value set -->
<ImageRuntime Condition="'$(PrimaryProjectWinmdImageRuntimeOverride)' == '' and '@(Language)' == 'C++'">WindowsRuntime 1.4</ImageRuntime>
<!-- This covers Managed Windows Runtime Component winmds -->
<ImageRuntime Condition="'$(PrimaryProjectWinmdImageRuntimeOverride)' == '' and '%(PackagingOutputs.WinMDFileType)' == 'Managed'">WindowsRuntime 1.4;CLR v4.0.30319</ImageRuntime>
<!-- This covers Native Windows Runtime Component winmds -->
<ImageRuntime Condition="'$(PrimaryProjectWinmdImageRuntimeOverride)' == '' and '%(PackagingOutputs.WinMDFileType)' == 'Native'">WindowsRuntime 1.4</ImageRuntime>
<!-- This covers Native Windows Runtime Component winmds for DynamicLibrary projects -->
<ImageRuntime Condition="'$(PrimaryProjectWinmdImageRuntimeOverride)' == '' and '%(PackagingOutputs.ProjectType)' == 'DynamicLibrary'">WindowsRuntime 1.4</ImageRuntime>
<!-- This provides an override -->
<ImageRuntime Condition="'$(PrimaryProjectWinmdImageRuntimeOverride)' != ''">$(PrimaryProjectWinmdImageRuntimeOverride)</ImageRuntime>
</_AppxWinmdFilesToHarvest>
</ItemGroup>
</Target>
With that block of code, the .NET libraries are deployed with the Background Application and the native code can successfully access the managed component.