如何在C#中处理null或者可选的dll struct参数

如何处理使用pinvoke从C#调用的dll方法中的可选struct参数? 例如, 此处的lpSecurityAttributes参数应在缺席时传递为null

传递struct的正确方法似乎是使用ref ,但它不能有可选参数,或者一般取null

有什么方法可以达到这个目的?

你有几个选择

1)使用class而不是struct

我认为这种方法最简单。 只需将struct声明为一个class

 [StructLayout(LayoutKind.Sequential)] public class CStruct { //member-list } 

然后声明你的方法:

 [DllImport("mydll.dll", OptionName = optionValue, ...)] static extern int DLLFunction(CStruct cStruct, ...); 

如果您的可选参数恰好是最后一个,则可以使用CStruct cStruct = null作为参数。 这允许您排除它而不是显式传递null 。 您还可以编写一个使用此方法的包装器方法,并确保可选参数最后。

2)使用IntPtrIntPtr.Zero

使用struct

 [StructLayout(LayoutKind.Sequential)] public struct CStruct { //member-list } 

并将您的方法声明为:

 [DllImport("mydll.dll", OptionName = optionValue, ...)] static extern int DLLFunction(IntPtr cStruct, ...); 

在非null情况下, 将结构编组为指针并调用方法:

 IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CStruct))); try{ Marshal.StructureToPtr(myCStruct, ptr, false); DLLFunction(ptr, ...); } finally { Marshal.FreeHGlobal(ptr); } 

null情况下,使用IntPtr.Zero调用方法:

 DLLFunction(IntPtr.Zero, ...); 

同样,如果这恰好是列表中的最后一个(或者使用包装器来实现),则可以使此参数成为可选参数。 通过使用IntPtr cStruct = default(IntPtr)作为参数来完成此操作。 ( default(IntPtr) 创建一个IntPtr.Zero 。)

3)重载您的方法以避免编组

使用2)中struct

只需为非null情况声明一个选项:

 [DllImport("mydll.dll", OptionName = optionValue, ...)] static extern int DLLFunction(ref cStruct, ...); 

和另一个null案例:

 [DllImport("mydll.dll", OptionName = optionValue, ...)] static extern int DLLFunction(IntPtr cStruct, ...); 

第一种方法在传递struct时会自动调用,第二种方法在传递IntPtr.Zero时会自动调用。 如果使用可选参数声明IntPtr版本(如上面2所示),则在排除cStruct参数时它会自动调用它。

4)使用unsafe原始指针

使用2)中的结构并声明您的方法(注意unsafe关键字):

 [DllImport("mydll.dll", OptionName = optionValue, ...)] static unsafe extern int DLLFunction(CStruct* cStruct, ...); 

在非null情况下,您传递&myCStruct ,并在null情况下为null 。 与1)中一样 ,如果此可选参数为last,则可以将参数声明为CStruct* cStruct = null以便在排除cStruct时自动传递null

感谢@dialer建议使用此方法。