【问题标题】:Equivalent of C sharp "public IntPtr pHandle = IntPtr.Zero;" to Delphi "hp: Pointer"相当于升 C 的“public IntPtr pHandle = IntPtr.Zero;”到德尔福“hp:指针”
【发布时间】:2014-11-13 18:59:01
【问题描述】:

经过一番研究,我翻译了

pHandle = IntPtr.Zero;

到德尔福

var
  pHandle: Pointer; 

当我在 Delphi 中进行调试时,我得到 $314328,当我在 C 语言上进行调试时,我得到一个整数值 134180640。谁能告诉我如何正确翻译到德尔福?

我在 Delphi 中调用的 Dll 函数是:

function SAAT_Open(pHandle: Pointer): Boolean; stdcall;

升C函数是:

[DllImport("RFIDAPI.dll", EntryPoint = "SAAT_Open")]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool SAAT_Open(IntPtr pHandle);

【问题讨论】:

  • 您的翻译是正确的(它与SAAT_Open() 的原始C 声明相匹配)。问题出在其他地方,比如您没有正确初始化 pHandle
  • 我也相信 pHandle 是问题所在,而不是如何正确启动它的一条线索。 pHandle 在调用“c# code”后得到一个值 if (rbnTCP.Checked) { bInit = RfidApi.SAAT_TCPInit(out pHandle, sReaderIP, iReaderPoint); }
  • 我已经在我的回答中解释了如何初始化它。就像你的代码已经做到了一样。通过调用 SAAT_TCPInit。从我的回答来看:如果 SAAT_TCPInit 返回 True 表示成功,那么句柄值将是有效的
  • @DavidHeffernan:假设他对SAAT_TCPInit() 的翻译是准确的并且正确地将pHandle 值输出到他的代码中。

标签: c# delphi pointers dll


【解决方案1】:

在 .NET 中,IntPtr 是指针类型的表示,它在后台由整数实现,因为它不能是实际的 .NET 指针(引用),因为必须管理“真实”引用。但它也不能是一个真正的整数,或者你可以对它进行数学运算,这是一种导致内存损坏的好方法。 (注意:此限制可能存在也可能不存在,具体取决于您使用的 C# 版本和/或 CLR。​​)

但是由于您不能将 IntPtr 视为整数,因此您可以对它做的唯一有用的事情是为它分配一个您从其他地方获得的值,或者将它传递给一些需要 IntPtr 的代码。 IntPtr.Zero 的存在是为了解决一个缺失但至关重要的场景:null 值。您不能将0 分配给它或针对0 对其进行测试,并且由于它不是参考,因此您不能针对null 进行分配或测试。所以他们将它创建为一个特殊的常量来表示“值为空的 IntPtr”。

如果你想在 Delphi 中做同样的事情,请声明指针,然后将其初始化为 nil

【讨论】:

  • IOW,在 Delphi 中 IntPtr 的等价物是 Pointer (或者在最近的版本中是 NativeInt,如果你想要一个整数),在 Delphi 中 IntPtr.Zero 的等价物是 @987654327 @(如果使用 NativeInt,则为 0)。
  • 您可以对 IntPtr 执行算术运算。而且在机器层面,指针和整数是无法区分的。
  • @DavidHeffernan:我刚刚检查过,显然IntPtr 上允许一些算术,令我惊讶的是,但很多简单的操作是被禁止的。与此最相关:将整数值分配给IntPtr 是一个错误,这就是IntPtr.Zero 存在的原因。
  • @Mason 只需进行一次强制转换即可分配一个 int。所以你可以写ip := (IntPtr)0;整数赋值对于指针来说有点不必要。算术很有用。仅在 .net 4 IIRC 中添加。
  • @David ...这可以解释为什么我认为它不起作用。我最后一次尝试是在 3.5 以下。
【解决方案2】:

经过一番研究,我翻译了

pHandle = IntPtr.Zero;

到德尔福

var
  pHandle: Pointer; 

谁能告诉我如何对 Delphi 进行正确的翻译?

C# 语法允许您在声明变量的同一语句中初始化变量:

IntPtr Handle = IntPtr.Zero;

在 Delphi 中,您不能在声明局部变量时对其进行初始化。所以需要先声明,然后初始化:

var
  Handle: Pointer;
....
Handle := nil;

在分配给非托管类型的局部变量之前,它的值是未定义的。


但是,如果您将nil 传递给SAAT_Open,那么它将失败。该函数需要一个非空句柄。因此,初始化为 nil 对您没有帮助。你需要做更多。您需要调用产生新句柄的函数。那是SAAT_TCPInit。您显示的将句柄初始化为空值的 C# 代码是不必要的。可能是因为 SAAT_TCPInit 被错误地翻译为使用 ref 参数作为句柄,而不是正确的翻译,即 out 参数。

虽然以上回答了您提出的问题,但无助于解决您的问题。你不需要一个空句柄,你需要一个实际的句柄。


当我在 Delphi 中进行调试时,我得到 314328 美元,当我在 C 语言上进行调试时,我得到一个整数值 134180640。

好吧,在pHandle = IntPtr.Zero 之后,您绝对不会在C# 中看到134180640 的值。您将看到值0。必须有一些其他代码来初始化句柄。大概是打电话给SAAT_TCPInit。你确实需要打那个电话。我相信你正在这样做。

句柄在程序的后续执行中不一定具有相同的值。并且不必在每个不同的程序中具有相同的值。句柄实际上是一个动态分配的指针,它的地址从一次运行到下一次是可变的。因此,如果它如您所观察到的那样变化,则无需担心。如果SAAT_TCPInit返回True表示成功,则句柄值有效。

【讨论】:

  • 是的,在 SAAT_TCPInit 之后,指针获得 134180640 或 C# 中的其他值,但是当我对 Delphi 执行相同操作时,我得到 314328 美元。不太明白美元符号的含义。另外,一旦我执行 SAAT_YTagSelect(hp, isenable, $01, sz, 4) ,它就不会激活标签,其中 hp 是指针
  • 我在您之前的一个问题中解释了 $ 前缀。我不明白您为什么不接受答案,也不回答我们问您的问题。也许您可以查看所有这些,接受最佳答案,并在此过程中了解$ 前缀。我想我回答了你在这里提出的问题。请您帮我一个忙并回复此评论。
  • 好的,抱歉,正在学习如何使用本网站。我认为如果它有助于解决问题,您将不得不接受答案。我现在,如果我接受答案,这并不意味着问题已经解决。大卫,感谢您的帮助,但请相信我,我正在努力理解所有这些回复。
  • 你真的应该回顾你以前的问题并接受最好的答案。你最近的所有问题都有很好的答案,应该被接受。本网站的目的是回答您提出的问题,而不是解决您的问题。请记住,我们看不到您的问题,因此您不能指望我们解决所有问题。我和这里的其他人真的很想帮助你,但只有你和我们一起工作才会奏效。
  • 好。我会让你继续处理你的其他问题。
猜你喜欢
  • 2017-08-27
  • 1970-01-01
  • 1970-01-01
  • 2014-07-08
  • 1970-01-01
  • 1970-01-01
  • 2014-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多