如何处理 null 或可选的 DLL 结构参数
How do I handle null or optional DLL struct parameters
如何处理使用 pinvoke 从 C# 调用的 dll 方法中的可选 struct
参数?例如,lpSecurityAttributes
parameter here 不存在时应传递 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
情况下,marshal the struct指向一个指针并调用方法:
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)
creates a IntPtr.Zero
。)
3) 重载您的方法以避免编组
使用 struct
,如 2).
简单地为非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),如果这个可选参数是最后一个,你可以将参数声明为CStruct* cStruct = null
以在排除cStruct
时自动传递null
。
感谢@dialer 推荐此方法
如何处理使用 pinvoke 从 C# 调用的 dll 方法中的可选 struct
参数?例如,lpSecurityAttributes
parameter here 不存在时应传递 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
情况下,marshal the struct指向一个指针并调用方法:
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)
creates a IntPtr.Zero
。)
3) 重载您的方法以避免编组
使用 struct
,如 2).
简单地为非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),如果这个可选参数是最后一个,你可以将参数声明为CStruct* cStruct = null
以在排除cStruct
时自动传递null
。
感谢@dialer 推荐此方法