我正在使用C#来调用DLL函数。
[DllImport("MyDLL.dll", SetLastError = true)]
public static extern uint GetValue(
pHandle handle,
ref somestruct a,
ref somestruct b);
如何为参数3传递null
参考?
当我尝试时,我收到编译时错误:
无法从
<null>
转换为ref somestruct。
我也试过IntPtr.Zero
。
答案 0 :(得分:5)
您有两种选择:
使somestruct
成为一个类,并将函数签名更改为:
[DllImport("MyDLL.dll", SetLastError = true)]
public static extern uint GetValue(
pHandle handle, somestruct a, somestruct b);
除非您可以null
作为a
和b
的值传递,否则不得更改任何其他内容。
为函数添加另一个重载,如下所示:
[DllImport("MyDLL.dll", SetLastError = true)]
public static extern uint GetValue(
pHandle handle, IntPtr a, IntPtr b);
现在,您可以使用IntPtr.Zero
调用该函数,以及对ref
类型的对象somestruct
调用:
GetValue(myHandle, ref myStruct1, ref myStruct2);
GetValue(myHandle, IntPtr.Zero, IntPtr.Zero);
答案 1 :(得分:0)
This answer建议让SomeStruct
成为一个班级。我想展示一个看起来效果很好的想法的实现......即使你不能改变SomeStruct
的定义(例如当它是System.Guid
这样的预定义类型时;也参见{{3 }})。
定义通用包装类:
[StructLayout(LayoutKind.Explicit)]
public sealed class SomeStructRef
{
[FieldOffset(0)]
private SomeStruct value;
public static implicit operator SomeStructRef(SomeStruct value)
{
return new SomeStructRef { value = value };
}
}
此处的基本想法与this answer相同。
将互操作方法定义更改为以下内容:
[DllImport("MyDLL.dll", SetLastError = true)]
public static extern uint GetValue(
pHandle handle,
ref SomeStruct a,
[MarshalAs(UnmanagedType.LPStruct)] SomeStructRef b);
第三个参数b
将是“可空的”。由于SomeStructRef
是引用类型,因此您可以传递null
引用。您还可以传递SomeStruct
值,因为存在从SomeStruct
到SomeStructRef
的隐式转换运算符。并且(至少在理论上),由于[StructLayout]
/ [FieldOffset]
编组指令,SomeStructRef
的任何实例都应该像SomeStruct
的实际实例一样进行编组。
如果是互操作专家,那么我会很高兴能够验证这项技术的合理性。
答案 2 :(得分:0)
另一个明显的解决方案是使用unsafe
代码并将interop方法声明更改为:
[DllImport("MyDLL.dll", SetLastError = true)]
unsafe public static extern uint GetValue(
pHandle handle,
ref somestruct a,
somestruct* b);
请注意,该方法现已标记为unsafe
,并且参数已从ref somestruct
更改为somestruct*
。
这具有以下含义:
只能从unsafe
上下文中调用该方法。例如:
somestruct s;
unsafe { GetValue(…, …, &s); } // pass a struct `s`
unsafe { GetValue(…, …, null); } // pass null reference
为了使上述工作正常,项目必须允许unsafe
代码(在项目设置中,或通过/unsafe
命令行编译器开关)。
使用unsafe
会导致无法验证的IL代码。 IIRC,这意味着加载这个程序集将需要完全信任(在某些情况下这可能会有问题)。
答案 3 :(得分:0)
从 .NET 5.0 开始,System.CompilerServices.Unsafe.NullRef<T>()
GetValue(myHandle, ref myStruct1, ref myStruct2);
GetValue(myHandle, ref Unsafe.NullRef<somestruct>(), ref Unsafe.NullRef<somestruct>());