如何在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)使用IntPtr
和IntPtr.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建议使用此方法。