【问题标题】:Converting C declaration to Delphi XE2将 C 声明转换为 Delphi XE2
【发布时间】:2014-08-14 19:49:48
【问题描述】:

我在将某些 C 声明转换为 Delphi XE2 以调用 DLL 中的函数时遇到问题。我翻译了 Visual Basic 源文件中的所有函数声明,但在测试它们时遇到了问题。一些函数返回 Long 值,但在调试我的代码时我观察到这些函数所涉及的返回值是不正确的。然后我转向 C 中的原始代码,在那里我找到了问题的根源:在原始 C 代码中的某个点有这样的声明:

typedef struct { } __RSI_CHANNEL;       
typedef __RSI_CHANNEL FAR* RSI_CHANNEL;

现在,一些函数返回 RSI_CHANNEL;这些函数的返回值如下:

return (RSI_CHANNEL)ws;

而ws被声明为:

rsiChannel FAR* ws = new FAR rsiChannel;

rsiChannel 是一个 typedef 结构。到目前为止,一切都很好......到目前为止,我想你们中的一些人可能已经认识到这是 PIMPL 成语。好的,根据源代码 cmets,我应该保存该返回值(RSI_CHANNEL)并针对 NULL 进行测试,并通过未触及的函数调用传递它......仅此而已......所以我认为它应该在 Delphi 中实现作为指针。但它不起作用。像这样的:

Type 
  RSI_CHANNEL = Pointer;

...{ later in implementation block }...

Function rsiInitWsock(HostName : PAnsiChar; port : Long) : RSI_CHANNEL; stdcall; external 'rsidll32';

没有编译错误,没有运行时错误。如果我调用这个函数,我会得到 Nil。

¿知道如何在 Delphi XE2 中实现这一点吗?并且,¿我做错了什么?提前致谢。

其他细节:

  • Delphi XE2(目标:Win32)
  • Windows 7 x64

我发现了问题;它与我的代码无关,从一开始就是正确的;它与 DLL 中的 ping 函数有关,它可以在笔记本电脑上工作,但它不想与台式机(Win7)一起工作,当它不工作时,它会中断对 DLL 的后续函数调用(为什么,我不知道......但)。无论如何,这不是一个完整的解决方案,但@DavidHeffernan 是第一个提出问题出在其他地方的想法,所以我接受他的回答主要是因为它为我指明了正确的方向。谢谢大家!

【问题讨论】:

  • rsiInitWsock 的 C 声明是什么样的?
  • 声明为:RSI_DLL RSI_CHANNEL RSI_API rsiInitWsock(char* hostname, WORD port); RSI_DLL是用于DLL中导出函数的宏,RSI_API = stdcall。
  • 我认为WORD -> UInt16,不是吗?您正在声明 long,这是一个有符号的 64 位整数。
  • @J... 只有在 C# 中 long 64 位宽
  • @DavidHeffernan 实际上我只是想知道我是否跨线了,它可能是 32 位的......我总是在 delphi 中使用Int64 - 无数的别名让我感到困惑!无论如何,它不是无符号的,也不是 16 位的word

标签: c delphi pointers dll opaque-pointers


【解决方案1】:

如上所述,您对RSI_CHANNEL 的处理是正确的。将其声明为 Pointer 是适当的操作。为了使类型安全性更强,您可以定义一个不同的类型而不是别名:

Type 
  RSI_CHANNEL = type Pointer;

如果port 参数真的是WORD,那么它映射到Delphi 中的Word

至于你的问题,它在别处。 RSI_CHANNEL 的翻译是准确的。

【讨论】:

  • 我应该补充一点,我尝试了几个选项...所有基于指针的选项都返回 Nil。由于 VB 实现使用 Long 作为返回类型,我使用基于整数的类型,直到我看到 C 声明。有趣的是,当我使用 Int64(和 UInt64)作为返回类型时,我得到了一些东西(一个大数字),其他一切都得到 0 或 Nil。
  • Int64 错误,因为您的指针是 32 位的。您的问题出在其他地方。
  • 如果您使用Int64,编译器将期望该函数使用EDX 和EAX 寄存器返回一个64 位值,然后将它们组合在一起以创建Int64 值。但是 32 位环境中的指针将仅使用 EAX 寄存器返回,使 EDX 寄存器未使用或者更糟的是随机的。这将导致“返回”较大的 Int64 值。
【解决方案2】:

由于RSI_CHANNEL 是 C 代码中的类型化指针,我将在 Delphi 中声明一个类似的类型化指针来匹配,而不是使用无类型的 Pointer(这也与使用 STRICT 的现代 Delphi 版本内联避免在 Win32 API 句柄类型(如 HWND 等)中使用无类型指针):

type
  RSI_CHANNEL = ^__RSI_CHANNEL;
  __RSI_CHANNEL = record
  end;       

Function rsiInitWsock(HostName : PAnsiChar; port : WORD) : RSI_CHANNEL; stdcall; external 'rsidll32';

【讨论】:

  • 那么你的问题出在其他地方,与指针本身无关。您将不得不调试 DLL 函数调用,并准确找出它真正返回的内容以及它是如何返回的。发生了一些可疑的事情。
  • 您显示的代码不应该按照您描述的方式运行。
  • @Remy 那些 cmets 是问题的焦点,应该出现在答案中。
猜你喜欢
  • 2012-02-05
  • 1970-01-01
  • 1970-01-01
  • 2015-09-30
  • 2011-11-22
  • 1970-01-01
  • 2013-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多