6

我正在使用 C# 调用 DLL 函数。

[DllImport("MyDLL.dll", SetLastError = true)]
public static extern uint GetValue(
        pHandle handle,
        ref somestruct a,
        ref somestruct b);

如何传递null参数 3 的引用?

当我尝试时,我收到一个编译时错误:

无法将 from 转换<null>为 ref somestruct。

我也试过了IntPtr.Zero

4

4 回答 4

6

你有两个选择:

  1. somestruct创建一个类,并将函数签名更改为:

    [DllImport("MyDLL.dll", SetLastError = true)]
    public static extern uint GetValue(
        pHandle handle, somestruct a, somestruct b);
    

    通常这不能改变任何其他东西,除了你可以传递 anull作为aand的值b

  2. 为函数添加另一个重载,如下所示:

    [DllImport("MyDLL.dll", SetLastError = true)]
    public static extern uint GetValue(
        pHandle handle, IntPtr a, IntPtr b);
    

    现在您可以使用 调用函数IntPtr.Zero,除了 aref类型的对象somestruct

    GetValue(myHandle, ref myStruct1, ref myStruct2);
    GetValue(myHandle, IntPtr.Zero, IntPtr.Zero);
    
于 2013-03-05T06:58:34.163 回答
0

这个答案建议SomeStruct上课。我想展示一个看起来很好用的想法的实现......即使你无法更改的定义SomeStruct(例如当它是预定义的类型时System.Guid;另请参阅这个答案)。

  1. 定义一个通用包装类:

    [StructLayout(LayoutKind.Explicit)]
    public sealed class SomeStructRef
    {
        [FieldOffset(0)]
        private SomeStruct value;
    
        public static implicit operator SomeStructRef(SomeStruct value)
        {
            return new SomeStructRef { value = value };
        }
    }
    

    这里的基本思想与拳击相同。

  2. 将您的互操作方法定义更改为以下内容:

    [DllImport("MyDLL.dll", SetLastError = true)]
    public static extern uint GetValue(
        pHandle handle,
        ref SomeStruct a,
        [MarshalAs(UnmanagedType.LPStruct)] SomeStructRef b);
    

然后第三个参数b将是“可空的”。由于SomeStructRef是引用类型,因此可以传递null引用。您还可以传递一个SomeStruct值,因为存在隐式转换运算符 from SomeStructto SomeStructRef。并且(至少在理论上),由于[StructLayout]/[FieldOffset]编组指令,任何实例都SomeStructRef应该像SomeStruct.

如果互操作专家能够验证这种技术的合理性,我会很高兴。

于 2015-05-17T21:36:58.503 回答
0

另一个明显的解决方案是诉诸unsafe代码并将互操作方法声明更改为:

[DllImport("MyDLL.dll", SetLastError = true)]
unsafe public static extern uint GetValue(
        pHandle handle,
        ref somestruct a,
        somestruct* b);

请注意,该方法现在已标记unsafe,并且参数已从 更改ref somestructsomestruct*

这具有以下含义:

  • 该方法只能从unsafe上下文内部调用。例如:

    somestruct s;
    unsafe { GetValue(…, …, &s);   }  // pass a struct `s`
    unsafe { GetValue(…, …, null); }  // pass null reference
    
  • 为了使上述工作有效,unsafe项目必须允许代码(在项目设置中或通过/unsafe命令行编译器开关)。

  • 使用unsafe会导致无法验证的 IL 代码。IIRC,这意味着加载此程序集将需要完全信任(在某些情况下可能会出现问题)。

于 2016-06-21T22:10:47.950 回答
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>());
于 2021-04-16T18:12:56.293 回答