You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在WPF桌面应用中调用Windows 10 UWP API遇到的问题求助

解决非打包桌面应用调用WinRT API的冲突问题

嘿,我之前也碰到过类似的坑,核心原因就是手动引用Windows.winmd这种老方式容易触发兼容性问题,现在微软有更靠谱的官方方案,咱们一步步来解决:

先搞懂你遇到的两个问题根源

  1. 特定版本winmd的语音命令API报错:你引用10.0.17134.0版本的winmd时,Geolocator能正常工作是因为这个API对无包身份的桌面应用做了兼容,但Package.Current.InstalledLocation依赖应用的包身份——非打包的桌面应用根本没有这个身份,所以必然抛出0x80073D54错误。
  2. 通用winmd的循环类型转发错误:根目录的Windows.winmd是通用版本,包含大量类型转发逻辑,但和桌面应用的.NET运行时环境适配不佳,就出现了CS0731这种循环依赖的报错。

正确姿势:用官方NuGet包替代手动引用winmd

微软现在明确推荐非打包桌面应用(WPF/WinForms这类)通过Microsoft.Windows.SDK.Contracts NuGet包来调用WinRT API,它会自动适配你的Windows版本,完全避开手动引用winmd的各种坑。

第一步:安装NuGet包

打开Visual Studio,右键你的项目→管理NuGet程序包,搜索Microsoft.Windows.SDK.Contracts,选择和你目标Windows版本匹配的包安装(比如你之前用的是17134,就找对应版本的包即可)。

第二步:调整代码适配非打包场景

关于Geolocator

安装完包后,直接用Windows.Devices.Geolocation.Geolocator就行,和你之前的写法完全一致,不需要额外配置:

using Windows.Devices.Geolocation;

// 示例调用代码
var locator = new Geolocator();
var position = await locator.GetGeopositionAsync();

关于语音命令的文件读取

既然是非打包应用,就别用Package.Current了——它是给UWP或打包桌面应用设计的。换用桌面应用的方式获取文件路径:
如果你的CustomVoiceCommandDefinitions.xml和exe放在同目录,用AppDomain.CurrentDomain.BaseDirectory拼接路径,再转成StorageFile即可:

using Windows.Storage;
using Windows.ApplicationModel.VoiceCommands;
using System.IO;

static async void LoadVoiceCommands()
{
    try
    {
        // 获取exe所在目录的文件绝对路径
        string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CustomVoiceCommandDefinitions.xml");
        // 把本地路径转换成WinRT的StorageFile
        StorageFile storageFile = await StorageFile.GetFileFromPathAsync(filePath);
        await VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(storageFile);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

额外要注意的细节

  1. 位置权限配置:非打包桌面应用要使用Geolocator,得声明位置权限。如果是WPF项目,添加一个app.manifest文件,然后加入这些内容:
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
            <!-- 声明支持的Windows 10版本 -->
            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
        </application>
    </compatibility>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
        <security>
            <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
                <requestedExecutionLevel level="asInvoker" uiAccess="false" />
            </requestedPrivileges>
            <!-- 声明位置权限 -->
            <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
                <privilege name="SeLocationPrivilege" />
            </requestedPrivileges>
        </security>
    </trustInfo>
    
    或者你也可以让用户手动在Windows设置里给你的应用授予位置权限。
  2. 语音命令的兼容性:确保你的Windows版本支持语音命令API,而且要把应用正确注册为语音命令的处理程序,不然安装命令定义可能会失败。

为啥不推荐手动引用Windows.winmd?

手动引用winmd本质上是旧的兼容方式,不同版本的SDK winmd包含的API实现不一样,和.NET运行时的类型转发逻辑很容易冲突(就是你碰到的CS0731错误)。用官方NuGet包是微软维护的方案,自动处理版本适配和依赖问题,省心多了。

内容的提问来源于stack exchange,提问作者sanjar14

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:16:51