MIDL 3.0 数组参数的反向 C++/WinRT ABI 参数顺序?

Reverse C++/WinRT ABI parameter order for MIDL 3.0 array parameter?

我有一个现有接口,我正尝试使用 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;
};};

考虑到 recommended order,这确实有意义。不幸的是,我没有能力改变现有接口的参数顺序。相反,我认为我可以使用 "classic" 样式来解决它:

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 的方式编写此接口?

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

如果您不能更改顺序,您能否编写一个包装器 class 来公开正确的顺序并简单地将调用转发到您现有的代码并反转参数?

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