生成的 COM 方法在参数上缺少 'out' 关键字

Generated COM method lacks 'out' keyword on a parameter

我正在尝试使用 C# 中的 Image Mastering API,但某些方法缺少 out 关键字,因此无法执行。

我通过执行以下操作生成了互操作代码:

在我撞墙之前它一直工作正常,这是我目前使用的代码:

using System;
using IMAPI2;

namespace ConsoleApp1
{
    internal static class Program
    {
        private static void Main(string[] args)
        {
            var master2 = new MsftDiscMaster2();

            var recorder2 = new MsftDiscRecorder2();

            var recorderUniqueId = master2[0];

            Console.WriteLine(recorderUniqueId);

            recorder2.InitializeDiscRecorder(recorderUniqueId);

            var recorder2Ex = (IDiscRecorder2Ex)recorder2;

            // this fails as pointer should be an 'out' parameter

            // System.NullReferenceException: 'Object reference not set to an instance of an object.'

            var discInformation = new IntPtr();

            recorder2Ex.GetDiscInformation(discInformation, out var byteSize);
        }
    }
}

IDiscRecorder2Ex::GetDiscInformation的原始签名:

HRESULT GetDiscInformation(
  [out] BYTE                          **discInformation,
  [out] ULONG_IMAPI2_DISC_INFORMATION *byteSize
);

Visual Studio生成的签名:

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetDiscInformation([Out] IntPtr discInformation, out uint byteSize);

我想手动编写接口代码是可行的,但这是一项艰巨的任务...

问题:

有没有办法让 Visual Studio 生成正确的签名?

此函数旨在 return 一个指向数组的指针和一个大小,并且这两个结果都通过 out 参数获得。 discInformation 参数是双重间接的:它指向一个存储指针的位置,该指针指向正在 returned 的数组的开头。

从技术上讲,我认为这可以翻译为

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetDiscInformation(
  [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out byte[] discInformation,
  [Out] out uint byteSize);

那你就可以了

GetDiscInformation(out var discInformation, out var byteSize);

但是,类型库转换器并没有这样做。所以你需要自己编组数组。看起来您根本没有正确执行此操作。 :

byte[] discInformation;
unsafe
{
    var di = new IntPtr();
    recorder2Ex.GetDiscInformation((IntPtr)&di, out var byteSize);
    discInformation = new byte[byteSize];
    Marshal.Copy(di, discInformation, 0, byteSize);
}