小编典典

如何处理null或可选的DLL结构参数

c#

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

传递的正确方法struct似乎是使用ref,但不能具有可选参数,也不能采用null一般参数。

有什么方法可以做到这一点?


阅读 252

收藏
2020-05-19

共1个答案

小编典典

您有几种选择

1)使用a class代替astruct

我认为这种方法是最简单的。只需将声明structclass

[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)重载您的方法以避免封送处理

struct2)中 使用a 。

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

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

另一种null情况:

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

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

4)使用原始指针 unsafe

使用结构为 2) ,并宣布你的方法(注意unsafe关键字):

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

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

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

2020-05-19