windows C++-通过 C++/WinRT 创作 COM 组件(四)

news/2024/10/20 15:10:07/
如何测试示例应用程序

生成应用程序,然后至少以管理员身份运行一次,以便使注册(和其他设置)代码运行。 执行此操作的一种方法是以管理员身份运行 Visual Studio,然后从 Visual Studio 运行应用。 在任务栏中右键单击 Visual Studio 以显示跳转列表,在跳转列表右键单击 Visual Studio,然后单击“以管理员身份运行”。 同意提示,然后打开项目。 运行应用程序时,会显示一条消息,指出是否在以管理员身份运行应用程序。 如果不是,则注册和其他设置不会运行。 该注册和其他设置必须至少运行一次,才能使应用程序正常工作。

无论是否在以管理员身份运行应用程序,按“T”使 toast 显示。 然后可以直接从弹出的 toast 通知或是从操作中心单击“回调 ToastAndCallback”按钮,这样会启动应用程序,实例化组件类并执行 INotificationActivationCallback::Activate 方法。

进程内 COM 服务器

上面的 ToastAndCallback 示例应用可充当本地(或进程外)COM 服务器。 这由 LocalServer32 Windows 注册表项进行指示,该项用于注册其组件类的 CLSID。 本地 COM 服务器在可执行二进制文件 (.exe) 中承载其组件类。

或者(并且可能更有可能),可以选择在动态链接库 (.dll) 中承载组件类。 采用 DLL 形式的 COM 服务器称为进程内 COM 服务器,由使用 InprocServer32 Windows 注册表项注册 CLSID 进行指示。

创建动态链接库 (DLL) 项目

可以通过在 Microsoft Visual Studio 中创建新项目,来开始创建进程内 COM 服务器的任务。 创建“Visual C++”>“Windows 桌面”>“动态链接库(DLL)”项目。

若要向新项目添加 C++/WinRT 支持,请执行修改 Windows 桌面应用程序项目以添加 C++/WinRT 支持中所述的步骤。

实现组件类、类工厂和进程内服务器导出

打开 dllmain.cpp,并向其添加如下所示的代码清单。

如果已具有一个实现 C++WinRT Windows 运行时类的 DLL,则表示已具有如下所示的 DllCanUnloadNow 函数。 如果要将组件类添加到该 DLL,则可以添加 DllGetClassObject 函数。

如果没有要保持与之兼容的现有 Windows 运行时 C++ 模板库 (WRL) 代码,则可以从显示的代码中删除 WRL 部分。

// dllmain.cppstruct MyCoclass : winrt::implements<MyCoclass, IPersist>
{HRESULT STDMETHODCALLTYPE GetClassID(CLSID* id) noexcept override{*id = IID_IPersist; // Doesn't matter what we return, for this example.return S_OK;}
};struct __declspec(uuid("85d6672d-0606-4389-a50a-356ce7bded09"))MyCoclassFactory : winrt::implements<MyCoclassFactory, IClassFactory>
{HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) noexcept override{try{return winrt::make<MyCoclass>()->QueryInterface(riid, ppvObject);}catch (...){return winrt::to_hresult();}}HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) noexcept override{// ...return S_OK;}// ...
};HRESULT __stdcall DllCanUnloadNow()
{
#ifdef _WRL_MODULE_H_if (!::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().Terminate()){return S_FALSE;}
#endifif (winrt::get_module_lock()){return S_FALSE;}winrt::clear_factory_cache();return S_OK;
}HRESULT __stdcall DllGetClassObject(GUID const& clsid, GUID const& iid, void** result)
{try{*result = nullptr;if (clsid == __uuidof(MyCoclassFactory)){return winrt::make<MyCoclassFactory>()->QueryInterface(iid, result);}#ifdef _WRL_MODULE_H_return ::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().GetClassObject(clsid, iid, result);
#elsereturn winrt::hresult_class_not_available().to_abi();
#endif}catch (...){return winrt::to_hresult();}
}
对弱引用的支持

如果类型实现 IInspectable或任何派生自 IInspectable 的接口,则 C++/WinRT,具体而言,winrt::implements 基结构模板,会实现 IWeakReferenceSource。

这是因为 IWeakReferenceSource 和 IWeakReference 旨在用于 Windows 运行时类型。 因此,只需通过向实现添加 winrt::Windows::Foundation::IInspectable(或派生自 IInspectable 的接口),即可为组件类启用弱引用支持。

实现从另一个接口派生的 COM 接口

接口派生是经典 COM 的一项功能(Windows 运行时中刻意不提供此功能)。 下例展示了接口派生的显示效果。 

IFileSystemBindData2 : public IFileSystemBindData { /* ... */  };

如果要编写需要实现的类,例如 IFileSystemBindData 和 IFileSystemBindData2,则表达的第一步是声明仅实现派生接口,如下所示。 

// pch.h
#pragma once
#include <Shobjidl.h>
...// main.cpp
...
struct MyFileSystemBindData :implements<MyFileSystemBindData,IFileSystemBindData2>
{// IFileSystemBindDataIFACEMETHOD(SetFindData)(const WIN32_FIND_DATAW* pfd) override { /* ... */ return S_OK; };IFACEMETHOD(GetFindData)(WIN32_FIND_DATAW* pfd) override { /* ... */ return S_OK; };// IFileSystemBindData2IFACEMETHOD(SetFileID)(LARGE_INTEGER liFileID) override { /* ... */ return S_OK; };IFACEMETHOD(GetFileID)(LARGE_INTEGER* pliFileID) override { /* ... */ return S_OK; };IFACEMETHOD(SetJunctionCLSID)(REFCLSID clsid) override { /* ... */ return S_OK; };IFACEMETHOD(GetJunctionCLSID)(CLSID* pclsid) override { /* ... */ return S_OK; };
};
...
int main()
...

下一步是在针对 MyFileSystemBindData 示例对 IID_IFileSystemBindData(基接口)直接或间接调用 QueryInterface 时,确保 QueryInterface 成功 。 为此,需要为 winrt::is_guid_of 函数模板提供专用化。

winrt::is_guid_of 是可变参数,因此可以为其提供接口列表。 下面介绍如何提供专用化,以使对 IFileSystemBindData2 的检查还包括对 IFileSystemBindData 的测试 。

// pch.h
...
namespace winrt
{template<>inline bool is_guid_of<IFileSystemBindData2>(guid const& id) noexcept{return is_guid_of<IFileSystemBindData2, IFileSystemBindData>(id);}
}// main.cpp
...
int main()
{...auto mfsbd{ winrt::make<MyFileSystemBindData>() };auto a{ mfsbd.as<IFileSystemBindData2>() }; // Would succeed even without the **is_guid_of** specialization.auto b{ mfsbd.as<IFileSystemBindData>() }; // Needs the **is_guid_of** specialization in order to succeed.
}

winrt::is_guid_of 的专用化在项目的所有文件中必须相同,并且在 winrt::implements 或 winrt::delegate 模板使用接口时可见 。 通常会将该内容放在一个通用头文件中。 


http://www.ppmy.cn/news/1511689.html

相关文章

Android常见的界面布局

目录 ​前言 1.线性布局LinearLayout 2.相对布局RelativeLayout 3.表格布局TableLayout 4.网格布局GridLayout 实现一个计算器界面 改Button按钮颜色 5.帧布局FrameLayout 前言 在Android应用程序中&#xff0c;界面是由布局和控件组成的。控件是功能单元&#xff0c;负…

Redis中String数据类型常用命令

目录 1. 基本操作 &#xff08;1&#xff09;新增 / 修改 数据 &#xff08;2&#xff09;获取数据 &#xff08;3&#xff09;删除数据 2. 计数与长度 &#xff08;1&#xff09;自增值&#xff08;当值为数字时&#xff09; &#xff08;2&#xff09;自减值&#xff08;当值…

我遇到的flutter问题以及答案(一)

1. 什么是 Flutter,为什么选择 Flutter? 答案: Flutter 是 Google 开发的开源 UI 软件开发工具包,用于跨平台的应用程序开发。开发者可以使用同一份代码库构建 Android、iOS、Web 和桌面应用程序。 选择 Flutter 的原因包括: 跨平台:一套代码可以运行在多个平台上。高性能…

Ps:高速缓存机制

Photoshop 的高速缓存 Cache技术利用缓存和分块的方法处理图像数据&#xff0c;通过合理设置高速缓存级别和拼贴大小&#xff0c;可以有效地提升软件在处理图像时的性能。 Ps菜单&#xff1a;编辑/首选项 Edit/Preferences “首选项”中提供了 8 种高速缓存级别。 增加高速缓存…

初识Linux · 基本指令(1)

目录 前言&#xff1a; 基本指令 1.1 pwd 1.2 ls 1.3 mkdir cd clear 1.4 touch 1.5 ls部分补充 1.6 whoami 1.7 有关目录以及路径 前言&#xff1a; 今天是Linux系列的第一章节&#xff0c;对于Linux的主线学习大概会更新两个半月左右&#xff0c;中间穿插着算法…

【面试题系列Vue02】Vue Router 路由都有哪些模式?各模式之间有什么区别?

官方解析 Vue Router 路由有三种模式&#xff1a; hash 模式&#xff1a;使⽤ URL 中的 hash&#xff08;即 # 后面的内容&#xff09;来作为路由路径。 在这种模式下&#xff0c;页面不会重新加载&#xff0c;只会更新 hash 值&#xff0c;并触发路由变化&#xff0c;从而渲…

xss.pwnfunction-Easy

目录 Ma Spaghet 代码 payload构造 结果 Jefff 代码 payload构造 方法一 方法二 结果 方法一 方法二 Ugandan Knuckles 代码 payload构造 结果 Ricardo Milos 代码 payload构造 结果 Ah Thats Hawt 代码 payload构造 结果 Ligma 代码 payload构造 结果…

26.实现一个算法删除已排序数组中的重复元素

26. Remove Duplicates from Sorted Array 题目 给定一个已排序的数组 nums,你需要原地删除重复出现的元素,使每个元素只出现一次,并返回移除后数组的新长度。  要求不能使用另一个数组分配额外的空间,必须使用O(1)的空间复杂度来完成此操作  例1: 给定的数组为= [1…