在本机 C++ 中将变量从 C# 编组到 void* 并在本机程序中更改 Managed/C# 中的变量值

问题描述

我有这个 C++ 代码

void ReleaseHandle(void* handle){
  Machine.motor motor =static_cast<Machine.IMotor*> (handle)
  if (motor == 0) throw;
  delete motor;
  handle = nullptr;
}

到目前为止,我可以使用 uint 作为数据类型在 Managed 中使用 PInvoke 将变量传递给 Releasehandle,问题是传递的变量的值不会改变。这个方法不是整个包,但我认为这足以说明我想要做什么。我需要更改值,因为如果托管端的指针没有更改,并且我决定再次从托管调用 releaseHandle,它将抛出堆栈跟踪,因为调用了 releaseHandle 并且未找到(释放)机器。

我尝试了很多将数据类型作为 ref 从托管传递的方法包括但不限于:

  • 无效*
  • [输入,输出]无效*
  • uint
  • 引用/输出单位
  • ref/out void*
  • UintPtr
  • 引用/输出 UintPtr

我希望当我像管理一样调用 ReleaseHandle

uint managedHandle = 123213124;
ReleaseHandle(managedHandle);
Console.WriteLine(managedHandle); // this outputs to 0

感谢您的帮助。

解决方法

您的基本问题是,您打算更改按值传递的变量。

话虽如此,正如 Matthew Watson 在对您的问题的评论中指出的那样,您必须调整您在 DLL 中调用的方法的接口,以获取指向您想要的指针位置的指针修改。

在您的示例中,您需要将指向 managedHandle 的指针传递给 ReleaseHandle

因此,您的 DLL 中的代码应如下所示:

void ReleaseHandle(void** handle) {
    *handle = nullptr; /* Note that here we dereference one level 
                          to modify the content of the location 
                          pointed at */
}

另一方面,在您的 C# 程序中,您应该使用以下内容导入函数:

[DllImport("YourLibrary.dll")]
static extern void ReleaseHandle(ref IntPtr handle);

并使用 ref 关键字调用它:

IntPtr value = IntPtr.Add(IntPtr.Zero,123456789);
ReleaseHandle(ref managedHandle);
Console.WriteLine(managedHandle); // this outputs to 0