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

问题描述 投票:14回答:1

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

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

有什么方法可以实现这一目标?

c# null interop pinvoke optional-parameters
1个回答
16
投票

您有几个选择

1)使用null代替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。您也可以编写一个使用该方法的包装方法,并确保可选参数排在最后。

2)使用nullIntPtr

使用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)。)

3)重载方法以避免封送处理>

[如[[2)中使用creates a IntPtr.Zero对于非IntPtr.Zero情况,只需声明一个选项:

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版本(如上述

2)

的底部所示),则当您排除IntPtr.Zero参数时,它将自动调用它。4)使用IntPtr的原始指针>

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

unsafe

在非unsafe情况下,您传递[DllImport("mydll.dll", OptionName = optionValue, ...)] static unsafe extern int DLLFunction(CStruct* cStruct, ...); ,而在null情况下仅传递&myCStruct。与
1)中一样,如果此可选参数为最后一个参数,则可以将参数声明为null以在排除null时自动传递CStruct* cStruct = null

感谢@dialer提出此方法。

© www.soinside.com 2019 - 2024. All rights reserved.