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

COM组件创建经历了一个渐进的过程,最开始的时候,程序员们可以使用标准的VC编译器创建;后来微软发布了ATL,使得程序员们可以使用ATL快捷的创建com组件,当然现在的winrt也包含对这项经典技术的支持。

默认情况下,C++/WinRT 在 COM 接口方面的表现如何

C++/WinRT 的 winrt::implements 模板是直接或间接派生运行时类和激活工厂的基础。

默认情况下,winrt::implements 会以无提示方式忽略经典 COM 接口。 因此,通过 QueryInterface (QI) 调用经典 COM 接口会失败,并出现 E_NOINTERFACE 错误。 默认情况下,winrt::implements 仅支持 C++/WinRT 接口。

winrt::IUnknown 是一个 C++/WinRT 接口,因此 winrt::implements 支持 winrt::IUnknown 接口 。
winrt::implements 默认情况下不支持 ::IUnknown 本身 。
稍后你将了解如何克服这些默认情况下不支持的情况。 但首先来看看一个代码示例,了解默认情况下会发生什么。

// Sample.idl
namespace MyProject 
{
    runtimeclass Sample
    {
        Sample();
        void DoWork();
    }
}

// Sample.h
#include "pch.h"
#include <shobjidl.h> // Needed only for this file.

namespace winrt::MyProject::implementation
{
    struct Sample : implements<Sample, IInitializeWithWindow>
    {
        IFACEMETHOD(Initialize)(HWND hwnd);
        void DoWork();
    }
}

下面是使用 Sample 类的客户端代码。

// Client.cpp
Sample sample; // Construct a Sample object via its projection.

// This next line doesn't compile yet.
sample.as<IInitializeWithWindow>()->Initialize(hwnd);
启用经典 COM 支持

好在要让 winrt::implements 支持经典 COM 接口,只需在包括任何 C++/WinRT 头文件之前包括 unknwn.h 标头文件即可。

可以显式这样做,也可以间接这样做,只需包括一些其他的头文件(例如 ole2.h)即可。 一个建议的方法是包括 wil\cppwinrt.h 头文件,该文件是 Windows 实现库 (WIL) 的一部分。 wil\cppwinrt.h 头文件不仅可确保在 winrt/base.h 之前包括 unknwn.h,而且可以让 C++/WinRT 和 WIL 了解彼此的异常和错误代码。

然后,可以对经典 COM 接口调用 as<>,以上示例中的代码将进行编译。

在上面的示例中,即使在客户端(代码使用类)中启用了经典 COM 支持,如果尚未在服务器(代码实现类)中启用经典 COM 支持,则客户端中对 as<> 的调用会失败,因为 IInitializeWithWindow 的 QI 会失败。

局部(非具现)类

局部类在同一编译单元(应用或其他二进制)中实现和使用;因此没有任何具现。下面是仅实现经典 COM 接口的局部类的示例。

struct LocalObject :
    winrt::implements<LocalObject, IInitializeWithWindow>
{
    ...
};

如果实现该示例,但不启用经典 COM 支持,则下面的代码将失败。 

winrt::make<LocalObject>(); // error: ‘first_interface’: is not a member of ‘winrt::impl::interface_list<>’

同样,IInitializeWithWindow 不会被识别为 COM 接口,因此 C++/WinRT 将忽略它。 对于 LocalObject 示例,忽略 COM 接口的结果意味着 LocalObject 根本没有接口 。 但每个 COM 类必须至少实现一个接口。 

COM 组件的简单示例

下面是使用 C++/WinRT 编写的 COM 组件的简单示例。 这是一个微型应用程序的完整代码清单,因此如果将其粘贴到新 Windows 控制台应用程序 (C++/WinRT) 项目的 pch.h 和 main.cpp 中,则可对其进行试用。 

// pch.h
#pragma once
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>

// main.cpp : Defines the entry point for the console application.
#include "pch.h"

struct __declspec(uuid("ddc36e02-18ac-47c4-ae17-d420eece2281")) IMyComInterface : ::IUnknown
{
    virtual HRESULT __stdcall Call() = 0;
};

using namespace winrt;
using namespace Windows::Foundation;

int main()
{
    winrt::init_apartment();

    struct MyCoclass : winrt::implements<MyCoclass, IPersist, IStringable, IMyComInterface>
    {
        HRESULT __stdcall Call() noexcept override
        {
            return S_OK;
        }

        HRESULT __stdcall GetClassID(CLSID* id) noexcept override
        {
            *id = IID_IPersist; // Doesn't matter what we return, for this example.
            return S_OK;
        }

        winrt::hstring ToString()
        {
            return L"MyCoclass as a string";
        }
    };

    auto mycoclass_instance{ winrt::make<MyCoclass>() };
    CLSID id{};
    winrt::check_hresult(mycoclass_instance->GetClassID(&id));
    winrt::check_hresult(mycoclass_instance.as<IMyComInterface>()->Call());
}

在下一部分,可以看看创建使用 C++/WinRT 实现基本组件类(COM 组件或 COM 类)和类工厂的最小控制台应用程序项目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值