示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载导读本文基于 Windows-universal-samples 仓库中的 ProxyStubsForWinRTComponents 示例深入讲解如何为 Windows RuntimeWinRT进程内组件in-process component创建代理与存根proxies and stubs使其能被 C、JavaScript 与 C# 三种语言无缝消费。读完本文你将掌握WinRT 组件服务器server的接口 IID 声明方式、代理/存根 DLL*_PS.vcxproj的构建链路、.def导出表的作用以及 C/CX、WRL、C#、JS 四种客户端消费同一组件的实际写法与构建、部署、运行步骤。示例定位跨语言消费的进程内组件该示例的核心目标是演示一种典型的 UWP 组件架构场景组件以进程内方式承载in-process但消费方横跨 C含 C/CX 投影与 WRL、C# 与 JavaScript 三种语言。要让同一份组件实现被不同语言正确投影和调用WinRT 需要借助标准的 COM 代理/存根机制进行接口注册与调用转发这正是本示例名字 ProxyStubsForWinRTComponents 的由来。从仓库目录结构看示例根目录下提供两套独立解决方案区别在于组件服务器Server的编写语言cpp/ProxyStubsForWinRTComponents.sln服务器使用 C/CXcppcx编写cs/ProxyStubsForWinRTComponents.sln服务器使用 C# 编写。两套解决方案内部都包含完全相同的四类工程Server组件服务器、PS代理/存根工程、C 客户端、C# 客户端与 JS 客户端。README 中提到的语言选择C、C# 或 JavaScript对应解决方案目录仓库实际随源码分发的是cpp与cs两套解决方案而js目录如 cpp/js内为客户端代码。组件服务器用显式 IID 定义跨语言接口接口与实现Bread 与 Oven组件服务器位于Microsoft.SDKSamples.Kitchen命名空间下围绕厨房烤箱业务模型定义了两组类型C/CX 与 C# 各有完全等价的实现类型定义说明OvenTemperaturecpp/Server/BreadTypes.h / cs/Server/OvenServer.cs枚举Low、Medium、High三档预热温度Dimensions同上值类型value struct含Depth、Height、Width三个double字段IBread/Breadcpp/Server/BreadServer.h只读属性Flavor口味IAppliance/IOven/Ovencpp/Server/OvenServer.hVolume只读属性、ConfigurePreheatTemperature、BakeBread、BreadBaked事件关键手法为接口显式声明 IID代理/存根机制的核心是 COM 接口注册因此接口的 IID接口标识符必须稳定且可预期。C/CX 版源码在接口声明处通过[uuid(...)]显式固定 IID源码注释明确写道Explicitly declare IIDs to make it easier to author the proxy stub interface registration见 OvenServer.hIAppliance332FD2F1-1C69-4C91-949E-4BB67A85BDC5IOven6A112353-4F87-4460-A908-2944E92686F3IBread699B1394-3CEB-4A14-AE23-EFEC518B088BC# 版则用[Guid(...)]特性声明同一组 IID见 cs/Server/OvenServer.cs 与 cs/Server/BreadServer.cs。两套语言的 IID 必须一致这正是后续代理/存根工程中PROXY_CLSID预处理器宏能正确注册接口的前提。服务器业务逻辑以事件驱动模拟异步烘焙OvenServer.cpp 展示了服务器侧的完整行为Volume属性由三个维度相乘得出Width * Height * DepthConfigurePreheatTemperature对温度参数做范围校验越界即抛出Platform::InvalidArgumentExceptionBakeBread根据当前温度档位选择预热时长Low→100 个时间单位、Medium→200、High→300随后通过ThreadPoolTimer::CreateTimer在后台线程完成烘焙再触发BreadBaked事件把新创建的Bread实例连同Oven一并交给订阅者。C# 实现OvenServer.cs与之一一对应同样的枚举范围校验、ThreadPoolTimer计时与BreadBaked事件触发。组件引入线程池回调意味着事件会在非 UI 线程触发客户端侧如何处理跨线程的 UI 更新正是示例场景要演示的重点之一。代理/存根工程跨语言调用的翻译层PS 工程结构代理/存根由独立的 DLL 工程产出即ProxyStubsForWinRTComponentsPS.vcxprojC 与 C# 解决方案各有一份内容一致见 cpp/Server/ProxyStubsForWinRTComponentsPS.vcxproj。从工程文件可以读出以下关键配置输出类型DynamicLibrary动态库TargetName为Microsoft.SDKSamples.Kitchen.Proxies即最终生成Microsoft.SDKSamples.Kitchen.Proxies.dll源文件编译dlldata.c、Microsoft.SDKSamples.Kitchen_i.c、Microsoft.SDKSamples.Kitchen_p.c三个文件——这三个文件是 MIDL 编译器处理 IDL 后生成的标准代理/存根代码_i.c为接口标识定义_p.c为代理/存根实现dlldata.c为 DLL 数据段注册表在仓库源码中它们属于构建产物MIDL 输入Midl项引用Microsoft.SDKSamples.Kitchen.idl即代理/存根代码由该 IDL 驱动生成预处理器宏PROXY_CLSIDIID___x_ABI_CMicrosoft_CSDKSamples_CKitchen_CIAppliance把代理类的 CLSID 直接绑定到IAppliance接口的 IID 上实现按接口注册代理类链接依赖rpcrt4.libRPC 运行时、runtimeobject.libWinRT 运行时对象部分配置还包含mincore.lib模块定义文件OvenServerPS.def。.def 导出表代理 DLL 的标准入口OvenServerPS.def 内容非常简短但语义明确LIBRARY Microsoft.SDKSamples.Kitchen.Proxies.dll EXPORTS DllCanUnloadNow PRIVATE DllGetClassObject PRIVATEDllGetClassObject是 COM 类工厂的标准入口供系统按 CLSID此处即PROXY_CLSID对应的IApplianceIID获取代理/存根类工厂DllCanUnloadNow供 COM 决定何时可安全卸载 DLL。这两个导出是任何代理/存根 DLL 的身份证也是连接 COM 运行时与 WinRT 接口注册表的桥梁。C# 服务器的 IDL 生成链路C# 编写的组件没有源码级 IDL 文件因此 cs/Server/ProxyStubsForWinRTComponents_server.csproj 在PostBuildEvent中调用了winmdidl工具call $(DevEnvDir)..\..\VC\vcvarsall.bat x86 winmdidl /outdir:$(ProjectDir)\ $(TargetPath)即构建 C# 服务器时先产出.winmd工程OutputType为winmdobj再由winmdidl把元数据反推出 IDL供 PS 工程的 MIDL 步骤消费。C/CX 与 C# 两条路线殊途同归最终都收敛到同一个 IDL → MIDL → 代理/存根 DLL 的构建流水线这是本示例最有价值的架构知识点。客户端消费四种语言的投影对照C/CX 投影Scenario1_OvenClientScenario1_OvenClient.xaml.cpp 演示了 C/CX 对进程内组件最典型的消费方式创建对象ref new Oven(dimensions)使用Dimensions值类型传参属性访问myOven-Volume直接以属性语法取值事件注册与注销可注册多个BreadBaked处理器C/CX 投影暴露事件注册令牌token通过返回值保存 token再用-精确移除——示例中注册了三个处理器并移除了第三个运行时可看到Event Handler 3不会触发调用方法BakeBread(Sourdough)后ThreadPoolTimer触发事件再次调用ConfigurePreheatTemperature(OvenTemperature::High)改变预热档位后再次烘焙。事件在后台线程触发处理器内通过Dispatcher-HasThreadAccess判断线程归属并用Dispatcher-RunAsync把 UI 更新 lambda 调度回 UI 线程——这是 UWP 跨线程 UI 更新的标准模式。WRL 客户端Scenario2_OvenClientWRL在同一解决方案的客户端 C 工程中还提供了Scenario2_OvenClientWRL场景文件见 cpp/cpp 目录。从工程结构推断该场景使用 WRLWindows Runtime C Template Library以 ABI 层 COM 接口方式消费同一个Oven组件与 Scenario1 的 C/CX 语言扩展写法形成对照适合需要精细控制引用计数与 COM 生命周期的场景。两个场景共用同一组件服务器恰好验证了代理/存根机制对同一接口的多种消费形态的兼容性。C# 与 JavaScript 客户端C# 客户端工程cs/cs与 JS 客户端cpp/js 或 cs/js同样包含Scenario1_OvenClient烤箱调用与Scenario2_CustomException自定义异常两类场景JS 客户端为 WinJS HTML 页面scenario1-oven-client.html/scenario2-custom-exception.html及其对应js文件以 JavaScript 的 WinRT 投影语法如new Kitchen.Oven(...)与事件订阅调用同一组件自定义异常场景从文件命名推断用于演示异常在跨语言调用链中如何经代理/存根传递——C 侧Platform::InvalidArgumentException与 C# 侧ArgumentException在服务器端抛出后客户端各语言投影如何捕获与呈现。系统要求README 明确列出运行环境约束见 README.md客户端ClientWindows 10服务器ServerWindows Server 2016 Technical Preview手机PhoneWindows 10。此外示例需要Visual Studio才能构建、Windows 10才能运行。仓库目标平台版本为10.0.22621.0见 PS 工程 与 C# 服务器工程构建环境需具备对应的 Windows SDK。构建与运行构建步骤若以 ZIP 方式下载示例请解压整个归档而不仅是目标示例所在文件夹——示例依赖仓库根目录的 SharedContent 共享资源工程中通过SharedContentDir宏向上查找 LICENSE 定位只解压单文件夹会导致共享依赖缺失启动 Visual Studio选择FileOpenProject/Solution在解压后的目录中依次进入Samples子文件夹 → 本示例子文件夹 → 首选语言的子文件夹C 或 C#双击其中的 Visual Studio 解决方案文件.sln按CtrlShiftB或选择BuildBuild Solution完成构建。运行步骤运行方式取决于你只需要部署还是部署并运行仅部署选择BuildDeploy Solution部署并运行调试按F5或选择DebugStart Debugging部署并运行不调试按CtrlF5或选择DebugStart Without Debugging。关键要点回顾显式 IID 是代理/存根的基础C/CX 用[uuid]、C# 用[Guid]声明完全一致的接口标识PS 工程再以PROXY_CLSID宏把代理类绑定到IAppliance的 IID构建流水线殊途同归C/CX 直接提供接口定义C# 由winmdidl从 winmd 反推 IDL两者都汇入「IDL → MIDL生成dlldata.c/_i.c/_p.c→ 代理 DLL」的同一条链路.def导出是 COM 入口DllGetClassObject与DllCanUnloadNow是代理/存根 DLL 被系统识别与加载的门面客户端形态多样但语义一致C/CX 的事件 token、WRL 的 ABI 直调、C# 与 JS 的投影语法消费的是同一组件、同一组接口这正是代理/存根机制价值的直接证明。如需深入阅读源码推荐按此顺序浏览README.md → OvenServer.h接口与 IID→ OvenServer.cpp服务器逻辑→ ProxyStubsForWinRTComponentsPS.vcxproj代理/存根构建→ Scenario1_OvenClient.xaml.cpp客户端投影与事件处理。赞分享示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载相关推荐CANN Runtime 多进程 IPC Notify 共享与进程白名单校验实战0_ipc_notify_withpid 示例深度解析CANN Runtime 多进程 IPC Notify 共享与进程白名单校验实战0_ipc_notify_withpid 示例深度解析 导读 本文基于 CANCANNAscend人工智能性能剖析系统编程CANN Runtime 内存管理与数据搬运实战指南基于 memory 示例集的 14 个场景深度解析CANN Runtime 内存管理与数据搬运实战指南基于 memory 示例集的 14 个场景深度解析 本指南围绕 CANN Runtime 开源仓库中 exCANNAscend人工智能性能剖析系统编程Azure文件共享数据同步AzCopy v10 sync命令高级用法Azure文件共享数据同步AzCopy v10 sync命令高级用法 AzCopy v10是一款功能强大的Azure存储数据传输工具其中sync命令为文件共上一篇P6Spy完整配置指南从基础设置到高级调优下一篇Go语言GUI开发终极指南Walk工具包从入门到精通创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
企业级 Agent 异步并发实战:从线上事故到高并发架构 1. 从一次线上事故说起:企业级 Agent 的异步并发到底难在哪去年下半年我接手了一个企业级 Agent 平台的稳定性治理工作,这个平台对外提供智能体编排、工具调用、多轮对话记忆、RAG 检索增强等能力,日均请求量在百万级别。上线初期一切看起来都… · 2026/9/25 8:46:54
微信聊天记录接入WorkBuddy:本地SQLite知识库构建指南 1. 为什么要把微信聊天记录接进 WorkBuddy微信聊天记录里藏着大量有价值的信息:客户报价、项目对接细节、地址电话、临时通知、文件传输记录。但微信本身对聊天记录的检索能力非常有限,跨会话搜索基本靠肉眼翻,时间一长,想找某条关… · 2026/9/25 8:46:48
从DeepSeek-OCR看多模态大模型:视觉Token效率革命下的ViT与CLIP协同演进 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 9:18:56
从传统IDE到Cursor的进化故事:用TaoToken统一Key打通AI从助手到伙伴的最后一公里 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 9:18:50
用大白话一步步教你:从零手写一个 MCP server 并接入 TaoToken 统一 Key /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 9:18:44
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37