如何编组 void* 参数,它可以是接口中的两个结构之一?

How to marshall out void* argument which can be one of two structs from interface?

我有一个非托管接口,我正尝试在 C# 中编组和使用。

还有一个函数我不确定如何正确编组:

IDataInfo :
public IUnknown {
...
    STDMETHOD_(BOOL, GetDataPackInfo) (UINT packIndex, void* pPackExtendedInfo) = 0;
...
}

void* 可以是两种不同结构之一:

struct DataExtendedInfoArchive {
    WORD Size;
    BOOL Archived;
    UINT SignalLength;
    BYTE Captured;
};

struct DataExtendedInfoStorage {
    WORD Size;
    FLOAT SignalFreq;
    UINT SignalLength;
    CHAR Code[4];
};

我是这样用 C# 实现的:

[StructLayout(LayoutKind.Sequential)]
public struct TrackExtendedInfoAudio
{
    int Size;
    [MarshalAs(UnmanagedType.Bool)]
    bool Archived;
    uint SignalLength;
    byte Captured;
}

[StructLayout(LayoutKind.Sequential)]
public struct TrackExtendedInfoVideo
{
    public int Size;
    public double SignalFreq;
    public uint SignalLength;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
    public StringBuilder Code;
}

问题是我不完全理解我将在 void* pPackExtendedInfo 中得到什么以及如何处理它,因此不知道如何为此函数编写正确的封送处理签名。

您可以将 void* 编组为 IntPtr:

private static extern bool GetDataPackInfo(uint packIndex, [In,Out] IntPtr pPackExtendedInfo);

并使用 Marshal.PtrToStructure (and Marshal.StructureToPtr) 方法之一复制结构:

IntPtr p = IntPtr.Zero;
GetDataPackInfo(..., p);
TrackExtendedInfoAudio audioInfo = Marshal.PtrToStructure<TrackExtendedInfoAudio>(p);

TrackExtendedInfoVideo videoInfo = Marshal.PtrToStructure<TrackExtendedInfoVideo>(p);

PS。而且我不确定 StringBuilder 是否适合 CHAR Code[4];.

托管函数签名(减去属性和装饰)应该是:

// make sure that the return is marshalled as UnmanagedTypes.Boolean.
bool GetDataPackInfo(uint packIndex, IntPtr pPackExtendedInfo);

要解压该结构,首先您需要确定您使用的是哪一个。幸运的是,每个的第一个成员是一个大小参数,它将提供关于结构大小的线索。要读取该大小,然后解压缩结构:

IntPtr ptr; // this is the pointer passed to your callback.

int cbSize = Marshal.ReadInt32(ptr, 0);
if (cbSize = Marshal.SizeOf(TrackExtendedInfoAudio))
{
    TrackExtendedInfoAudio s = Marshal.PtrToStructure(ptr, typeof(TrackExtendedInfoAudio)) 
             as TrackExtendedInfoAudio;
    // Processing...
}
else if (cbSize == Marshal.SizeOf(TrackExtendedInfoVideo))
{
    TrackExtendedInfoVideo s = Marshal.PtrToStructure(ptr, typeof(TrackExtendedInfoVideo)) 
             as TrackExtendedInfoVideo;
    // Processing...
}
else
{
    // unknown struct
}