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