0

我有一个正在尝试使用 MIDL 3.0 定义的现有接口。它的一种方法具有此 C++ 签名:

HRESULT GetArray(struct FOO** outArray, uint32_t* outSize);

我尝试将其翻译为 IDL,如下所示:

namespace Examples {
    struct Foo {
         Int32 n1;
         Int32 n2;
    };
    interface IExample {
        void GetArray(out Foo[] array);
    }
}

但是,生成的 C++/WinRT ABI 具有相反顺序的参数:

template <> struct abi<Examples::IExample>{ struct type : IInspectable
{
    virtual HRESULT __stdcall GetArray(uint32_t* __arraySize, struct struct_Examples_Foo** array) noexcept = 0;
};};

考虑到这是推荐的顺序,这确实有意义。不幸的是,我没有能力改变现有接口的参数顺序。相反,我认为我可以使用“经典”风格来解决它:

namespace Examples {
    [uuid("d7675bdc-7b6e-4936-a4a0-f113c1a3ef70"), version(1)]
    interface IExample {
        HRESULT GetArray(
            [out, size_is(, *size)] Foo** array,
            [out] unsigned long* size
        );
    }
}

但是,这被 MIDL 编译器拒绝:

MIDL4058: [msg]The size parameter of an array parameter must appear directly before the array parameter. [context]size

如何在 IDL 中编写此接口以产生正确的 ABI?

4

1 回答 1

1

WinRT 对数组参数的排序有一个严格的 ABI 定义,正如您所发现的那样,(size, pointer)而不是相反。没有办法改变这一点,因为所有的投影(例如 .NET、JavaScript 和 C++/CX)都期望这个顺序,如果以错误的顺序传递,将会灾难性地失败。

如果您无法更改顺序,您是否可以编写一个包装类来公开正确的顺序并简单地将调用转发到您现有的代码中,同时参数颠倒过来?

做不到这一点,如果您只关心 C++(可能还有 C# 客户端),还有另一种方法可以支持这一点。也就是说,您可以定义一个经典 COM 接口并让您的 WinRT 对象也实现该接口,而不是为此方法定义 WinRT 接口。然后,该 COM 接口的 WinRT 对象 QI 的客户端可以按您需要的顺序传递参数。

于 2018-07-23T03:25:28.143 回答