gpt4 book ai didi

c# - C# 中的结构对齐

转载 作者:行者123 更新时间:2023-11-30 02:41:47 25 4
gpt4 key购买 nike

我正在使用 SQL VDI 并尝试通过 COM 接口(interface)将结构从 C# 传递到 C++。该结构在 C++ header 中定义为:

#pragma pack(8)
struct VDConfig
{
unsigned long deviceCount;
unsigned long features;
unsigned long prefixZoneSize;
unsigned long alignment;
unsigned long softFileMarkBlockSize;
unsigned long EOMWarningSize;
unsigned long serverTimeOut;
unsigned long blockSize;
unsigned long maxIODepth;
unsigned long maxTransferSize;
unsigned long bufferAreaSize;
} ;

为了模拟这一点,我在 C# 中将结构定义为:

[StructLayout(LayoutKind.Explicit)]
public struct VDConfig
{
[FieldOffset(0)]
public uint deviceCount;
[FieldOffset(4)]
public uint features;
[FieldOffset(8)]
public uint prefixZoneSize;
[FieldOffset(12)]
public uint alignment;
[FieldOffset(16)]
public uint softFileMarkBlockSize;
[FieldOffset(20)]
public uint EOMWarningSize;
[FieldOffset(24)]
public uint serverTimeout;
[FieldOffset(28)]
public uint blockSize;
[FieldOffset(32)]
public uint maxIODepth;
[FieldOffset(36)]
public uint maxTransferSize;
[FieldOffset(40)]
public uint bufferAreaSize;
}

我还尝试将结构定义为 LayoutKind.Sequential 并尝试使用 Pack=8。但是我定义了结构,当我试图将它传递给函数时,它失败了并且我收到错误“Alignment must be 2**n and <= system allocation granularity.”我尝试将接受结构的函数定义为:

int CreateEx([MarshalAs(UnmanagedType.LPWStr)]string instanceName,
[MarshalAs(UnmanagedType.LPWStr)]string name,
IntPtr config);

int CreateEx([MarshalAs(UnmanagedType.LPWStr)]string instanceName,
[MarshalAs(UnmanagedType.LPWStr)]string name,
ref VDConfig config);

无论哪种定义,我都得到了相同的结果。谁能告诉我我在这里做错了什么?

编辑:仔细观察,我还收到错误“设备计数必须在 [1..64] 中。”我将设备计数设置为 1 并且与上面的错误一致,看起来该函数根本没有得到我的结构。不知道这是否有帮助,但也许它会激发某些人的灵感。

根据请求,这里是接口(interface)结构。在 C++ 中:

MIDL_INTERFACE("d0e6eb07-7a62-11d2-8573-00c04fc21759")
IClientVirtualDeviceSet2 : public IClientVirtualDeviceSet
{
public:
virtual HRESULT STDMETHODCALLTYPE CreateEx(
/* [in] */ LPCWSTR lpInstanceName,
/* [in] */ LPCWSTR lpName,
/* [in] */ struct VDConfig *pCfg) = 0;

virtual HRESULT STDMETHODCALLTYPE OpenInSecondaryEx(
/* [in] */ LPCWSTR lpInstanceName,
/* [in] */ LPCWSTR lpSetName) = 0;

};

还有我的 C# 版本:

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("d0e6eb07-7a62-11d2-8573-00c04fc21759")]
public interface IClientVirtualDeviceSet2
{
void CreateEx([In, MarshalAs(UnmanagedType.LPWStr)]string instanceName,
[In, MarshalAs(UnmanagedType.LPWStr)]string name,
[In]ref VDConfig config);

void OpenInSecondaryEx([MarshalAs(UnmanagedType.LPWStr)]string instanceName,
[MarshalAs(UnmanagedType.LPWStr)]string lpSetName);
}

最佳答案

对于遇到此问题的任何其他人,这就是答案:

正如您在 vdi.h 中看到的那样, IClientVirtualDeviceSet2 “继承”自 IClientVirtualDeviceSet .就 COM 而言,没有接口(interface)继承这回事。

因此,当调用 CreateExIClientVirtualDeviceSet2 ,你实际上是在调用 CreateIClientVirtualDeviceSet (因为 Create 是组合 vtable + IClientVirtualDeviceSetIClientVirtualDeviceSet2 中的第一个方法)。这就是您最终得到无效参数的原因。

解决这个问题的方法是创建一个接口(interface)(IClientVirtualDeviceSet2),其中包含所有方法,IClientVirtualDeviceSet首先,然后是两个IClientVirtualDeviceSet2方法(显然是按顺序)。这确保了何时 CreateEx()被调用,它使用正确的 DispId .

我确定您可以使用继承并相应地设置 DispIdAttribute:

https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dispidattribute(v=vs.110).aspx

但可能没什么意义。

关于c# - C# 中的结构对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27705778/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com