【问题标题】:P/Invoke Marshalling an Out void*P/Invoke Marshalling an Out void*
【发布时间】:2014-05-26 18:32:18
【问题描述】:

我有以下 C 函数定义:

EXPORT CreateWindow(const wchar_t* applicationTitle, void* windowHandle) {
    // Some preconditions & other stuff here

    windowHandle = RENDER_COMPONENT.Window.CreateNew(cstr_to_wstring(applicationTitle));
    return true;
}

该函数通过 P/Invoke 调用。 P/Invoke函数定义如下:

[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "CreateWindow", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _CreateWindow([MarshalAs(UnmanagedType.LPWStr)] string applicationTitle, [Out] out IntPtr windowHandle);

这个函数的用法是:

IntPtr windowHandle;
bool windowCreationSuccess = _CreateWindow(Engine.ApplicationTitle, out windowHandle);

我的问题是 windowHandle 在 C# 代码中始终等于 IntPtr.Zero,我猜这意味着它不会以某种方式从 C++ 到 C# 端“复制”。它是在 C 函数中设置的(我用调试器查看过)——它实际上是一个 HWND。

P/Invoke 总是让我感到困惑 - 我确定我在复制结构而不是对它的引用或其他什么方面做错了,但我不太清楚什么/在哪里。

【问题讨论】:

  • 这与 user32 中的 CreateWindowEx 方法完全不同吗? pinvoke.net/default.aspx/user32/CreateWindowEx.html
  • C 代码已损坏,当您从 C 程序调用它时,它也无法正常工作。正确的参数声明是HWND*,比void** 更漂亮。在尝试 pinvoke 之前,始终对 C 代码进行单元测试。

标签: c# pinvoke


【解决方案1】:

C 仅使用按值传递。这意味着调用者永远无法看到您对windowHandle 的分配。对于任何呼叫者都是如此,而不仅仅是托管的 pinvoke。

您需要更改 C 函数以接收窗口句柄变量的地址。像这样:

EXPORT CreateWindow(const wchar_t* applicationTitle, HWND* windowHandle) {
    // Some preconditions & other stuff here
    *windowHandle = RENDER_COMPONENT.Window.CreateNew(cstr_to_wstring(applicationTitle));
    return true;
}

然后问题中的 C# 代码匹配。

但是你的 C 代码很奇怪。为什么无条件返回true?如果它总是正确的,为什么还要返回一个布尔值。坦率地说,返回 HWND 会更干净。

【讨论】:

  • 感谢您的回答。为了解决您的 cmets:返回值并不总是 true,我为简洁而省略的一些前提条件可能会返回 false。它也只是遵循我用于 P/Invoke 调用的一般模式。此外,我试图保持这个接口与平台无关,因此是 void*(不是 HWND)。
猜你喜欢
  • 1970-01-01
  • 2013-10-19
  • 2023-03-30
  • 1970-01-01
  • 2014-04-22
  • 1970-01-01
  • 1970-01-01
  • 2011-10-15
  • 1970-01-01
相关资源
最近更新 更多