WinUI3 で Azure.Communication.Calling.WindowsClient を使おうとすると例外で落ちる

Windows上のWinUI3アプリでAzure Communication Services(以下ACS)を使おうと思ってサンプル通りに進めようとすると、CallClientのインスタンスを作る際に例外になってしまいます。

GitHubにあるサンプルは問題なく動作するのに一体何が違うんだ?と悩んでたんですが、結論から言えばWinUI3+.NET 8以降でのターゲットフレームワークの問題でした。(サンプルは .NET 6)
参考までに投げられる例外は以下のような感じです。

{
  "TypeName": "WinRT.ActivationFactory`1",
  "Message": "The type initializer for 'WinRT.ActivationFactory`1' threw an exception.",
  "Data": {},
  "InnerException": {
    "ErrorCode": -2147221164,
    "Message": "クラスが登録されていません (0x80040154 (REGDB_E_CLASSNOTREG))",
    "Data": {},
    "InnerException": null,
    "HelpLink": null,
    "Source": "System.Private.CoreLib",
    "HResult": -2147221164,
    "StackTrace": "   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode)\r\n   at WinRT.BaseActivationFactory..ctor(String typeNamespace, String typeFullName)\r\n   at WinRT.ActivationFactory`1..ctor()\r\n   at WinRT.ActivationFactory`1..cctor()"
  },
  "HelpLink": null,
  "Source": "Azure.Communication.Calling.WindowsClient.interop",
  "HResult": -2146233036,
  "StackTrace": "   at WinRT.ActivationFactory`1.ActivateInstance[I]()\r\n   at Azure.Communication.Calling.WindowsClient.CallClient..ctor()\r\n   at App1.MainWindow.myButton_Click(Object sender, RoutedEventArgs e)"
}

結局原因は何だったのかというと、ACSのネイティブコードがコピーされてないことが原因でした。本来だったら以下のようなファイルが nativeAssetsに出力されるはず。

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          2024/11/16     7:14       17329184 Azure.Communication.Calling.WindowsClient.dll
-a---          2024/11/16     7:14        6294064 RtmCodecs.dll
-a---          2024/11/16     7:14        1720856 RtmMediaManager.dll
-a---          2024/11/16     7:14         681512 RtmMvrMf.dll
-a---          2024/11/16     7:14        1145904 RtmPal.dll
-a---          2024/11/16     7:14       18551840 RTMPLTFM.dll
-a---          2024/11/16     7:14        5109832 skypert.dll
-a---          2024/11/16     7:14        2493000 SlimCV.dll
-a---          2024/11/16     7:14         418848 ssScreenVVS2.dll

で、なぜ出力されないのかというと上記のネイティブアセットが .NET 6だからぽい。というわけでターゲットフレームワーク辺りの問題が解決したらいけるはず…
試した結果 .csproj ファイル内の RuntimeIdentifiers を旧形式にして NETSDK1083 を回避するために UseRidGraph を True にしたり CopyLocalLockFileAssemblies を True にしたりします。

<PropertyGroup>
    <RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
	<UseRidGraph>true</UseRidGraph>
    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
	<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

リビルドすると必要ファイルが出力フォルダーにコピーされて無事動作するようになる…と思います。

WinRTはWindows 8の時から触ってるけど、Windowsネイティブ(?)であれこれしようとすると相変わらずしんどいですね。

追記:ビルドは通るようになったけど、結局 .NET 8+ だとWindowsClient でカメラやオーディオのデバイス取れなくてダメだわ(

さらに追記:Calling SDK標準だとネイティブアセットが .net6.0-windowsフォルダでコピーされるので、 ランタイムのバージョンに合わせたフォルダ( .net8.0-windowsなど)にコピーすればよさそう。サンプルはビルド後イベントに xcopy でネイティブアセットをコピーしてるので修正したらいけそう?(手動コピーしたら手元では .net 8.0 でも一応動作した)
※ しかし .net 6.0 でビルドしないとそもそもネイティブアセットが無いか?何かしら .net 6.0のネイティブアセットをコピーしてこないとダメかもしれない

xcopy $(OutDir)\runtimes\win10-x64\nativeAssets\net6.0-windows\*.* $(OutDir)\Appx\runtimes\win10-x64\nativeAssets\net8.0-windows\*.* /Y

コメントを残す