【问题标题】:Passing Pointer from C++ to Delphi DLL将指针从 C++ 传递给 Delphi DLL
【发布时间】:2016-01-06 14:00:58
【问题描述】:

我已搜索并找不到任何可以回答我的问题的内容。如果我的问题的措辞不正确,请提出建议,我会重新措辞。我不自称是指针专家,但我正在做的事情似乎相当简单,并且在此处提供的指导范围内:

Pointers and Pointer Types (Delphi)

我有一个用 Delphi 编写的 DLL。它是从 C++ 应用程序 (sfms_trayicon.exe) 调用的。有问题的函数是指针类型,它有一个参数,一个指针。指针作为通用指针传递,然后转换为 hWnd 指针。然后将其取消引用到 hWnd 类型的变量。这是实际的功能代码:

    function sfms_ui_init(FhWnd: Pointer): Pointer;
    var
      pCallinghWnd: ^hWnd;          // hWnd pointer type

    begin
      try
        // Get the hWnd passed as a generic pointer
        pCallinghWnd := FhWnd;           // Cast the general pointer to a hWnd pointer
        CallinghWnd := pCallinghWnd^;    // De-reference the pointer (CallinghWnd is a global var of type hWnd)
      finally

      end;
    end;

传递给函数的指针是有效的。对 hWnd 指针类型的分配有效。取消引用偶尔会起作用,但大多数时候会产生访问冲突:

我的问题,我希望它足够具体,为什么取消引用指针的行偶尔会起作用,但大多数时候会引发访问冲突? 我想后续行动会是,我需要做什么才能使其工作?

谢谢

【问题讨论】:

  • 请不要描述调用代码,并向我们保证它是正确的。你可能是错的。请出示。请出示完整的minimal reproducible example。请互操作的双方。 DLL 代码可以减少到 20 行,调用代码类似。不匹配的明显原因是调用约定错误(这看起来像register)或者您没有传递您认为正在传递的内容。例如,传递包含HWND 的变量的地址肯定是错误的。按值传递HWND。此外,尽管您承诺这样做,但您的函数不会返回任何内容。
  • .... 你的尝试/最终是毫无意义的。看起来你正在随机尝试一些东西。是时候退后一步了。
  • @David Heffernan 这是一个开发练习,try/finally 稍后会充实或删除,只是作为一个地方标记。虽然达到了这一点,但不要随意尝试东西:)我认为您可能是正确的,因为指针参数不是它应该是的(尽管该函数有时会在没有 AV 的情况下执行)。我看过 Remy 的建议,我认为它是合理的,并且会让 C++ 例程的作者在第一个实例中简单地传递一个 Windows 句柄作为参数。感谢您的回复。
  • 嗯,我的评论中也有这个建议。
  • @David Heffernan,是的,我也应该说,当我说“我认为你可能是正确的”时。我也应该说我看过雷米和你的建议,我认为这些建议是合理的......这并不是轻微的。

标签: function delphi pointers dll


【解决方案1】:

Delphi 和 C++ 是强类型语言。由于您的函数需要一个指向 HWND 的指针作为输入,因此请声明它,例如:

type
  PHWND = ^HWND;

function sfms_ui_init(FhWnd: PHWND): Pointer;
begin
  CallinghWnd := FhWnd^;
  //...
end;

或者更好:

function sfms_ui_init(var FhWnd: HWND): Pointer;
begin
  CallinghWnd := FhWnd;
  //...
end;

通过指针/引用传递HWND 变量是没有意义的,除非函数需要直接修改调用者的HWND 变量。 HWND 已经是一个指针,所以在大多数情况下应该按值传递:

function sfms_ui_init(FhWnd: HWND): Pointer;
begin
  CallinghWnd := FhWnd;
  //...
end;

为什么取消引用指针的行偶尔会起作用,但大多数时候会引发访问冲突?我想后续行动会是,我需要做什么才能使其工作?

没有看到您的 C++ 代码,就无法真正回答这个问题。但是,由于您的函数需要一个 指向 HWND 的指针,但将其作为通用的无类型 Pointer 接受,因此 C++ 代码可能没有将正确的内存地址传递给该指针。例如,如果 C++ 代码这样做:

HWND hWnd = ...;
sfms_ui_init(hWnd); // passing wrong address!

什么时候应该这样做:

HWND hWnd = ...;
sfms_ui_init(&hWnd); // passing correct address!

Pointer 在 Delphi 中转换为 C++ 中的 void*,它没有类型信息。 HWND已经是一个指针,任何指针都可以传递给void*,所以编译器允许赋值,但是会导致运行时错误。

更有理由摆脱无类型指针并改用类型指针。使用正确的类型可以让 C++ 编译器验证传递给函数的指针值类型是否正确,例如:

// given: function sfms_ui_init(FhWnd: PHWND): Pointer;
// or: function sfms_ui_init(var FhWnd: HWND): Pointer;

HWND hWnd = ...;
sfms_ui_init(hWnd); // compiler error!
sfms_ui_init(&hWnd); // OK

// given: function sfms_ui_init(FhWnd: HWND): Pointer;

HWND hWnd = ...;
sfms_ui_init(hWnd); // OK
sfms_ui_init(&hWnd); // compiler error!

【讨论】:

  • 你完全正确。事后看来,将指针传递给指针没有真正意义。 C++ 例程的作者希望保持他的应用程序操作系统不可知,因为它可能被移植到 OSX,但事实上我们还没有尝试简单地传递一个窗口句柄而不是一个指向指针的指针并将它转换为一个类型化的指针和将其引用到 Windows 句柄似乎只是传递 Windows 句柄的一种过于复杂的方式。感谢您深思熟虑的回应。虽然它似乎是一个 BFO(显而易见的闪光),但它确实把这个问题放在了一个明智的角度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-30
  • 1970-01-01
  • 1970-01-01
  • 2018-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多