【问题标题】:C++ to Delphi Header file translation: function with pointer to voidC++ 到 Delphi 头文件翻译:带有指向 void 的指针的函数
【发布时间】:2013-10-09 19:10:32
【问题描述】:

我在翻译 c++ 头文件时遇到问题。当我执行我的 Delphi 代码时,它返回代表“无效参数”的代码 125。我将解释到目前为止我所做的事情:

头文件(片段):

IDSEXP is_AOI(HIDS hCam, UINT nCommand, void *pParam, UINT SizeOfParam);

我的翻译:

function is_AOI(hCam: Cardinal; Command: Cardinal; Param: Pointer; ParamSize: Cardinal): integer; cdecl; external 'ueye_api.dll';

示例 c++ 代码:

IS_SIZE_2D imageSize;
imageSize.s32Width = m_nSizeX;
imageSize.s32Height = m_nSizeY;
is_AOI(m_hCam, IS_AOI_IMAGE_SET_SIZE, (void*)&imageSize, sizeof(imageSize));

我的代码:

var
  size2D: TSize2D;

size2D.S32X := maxWidth;
size2D.S32Y := maxHeight;
ret := is_AOI(cam, IS_AOI_IMAGE_SET_SIZE, Pointer(@size2D), SizeOf(size2D));

c++ 结构:

typedef struct 
{
    INT s32Width;
    INT s32Height;
} IS_SIZE_2D;

还有我的翻译:

TSize2D = record
  S32X, S32Y: integer;
end;

【问题讨论】:

    标签: c++ delphi header-files delphi-xe4


    【解决方案1】:

    虽然pointer 的转换是正确的,但我通常发现用无类型的var 参数替换*void 更优雅。

    hCam是一个Handle,实际上是一个指针;您应该为此使用NativeUintUIntPtr,否则代码将中断 64 位。请注意,THandle 仅适用于 Windows API 调用,这是一个 Google dll。

    Delphi 7 警告
    Delphi 7 seems to think that SizeOf(NativeUInt) = 8, 这已在 D2009 中修复,您可以通过

    修复它
    {$IFNDEF VER200}  //anything prior to Delphi 2009
    type
      NativeUInt = Cardinal;
      NativeInt = Integer;
    {$ENDIF}
    

    IDSEXP定义如下:
    请注意,调用约定仅为 32 位的 cdecl。在 64 位中使用默认的 Win64 调用约定。

    #if defined __i386__
            #define IDSEXP    __attribute__((cdecl)) INT
            #define IDSEXPUL  __attribute__((cdecl)) ULONG
    #else
            #define IDSEXP    INT
            #define IDSEXPUL  ULONG
    #endif
    

    但是根据@David 的评论,x64 忽略调用约定关键字因为只有一个,所以定义应该如下所示:

    function is_AOI(hCam: NativeUInt; 
                    Command: Cardinal; 
                    var Param; 
                    ParamSize: Cardinal): integer; 
                    cdecl; external 'ueye_api.dll';
    

    你现在可以这样称呼它:

    ret:= is_AOI(cam, IS_AOI_IMAGE_SET_SIZE, size2D, SizeOf(size2D));
    

    真正导致您的功能失败的原因
    起初我以为错误 125 是运行时错误,但它实际上是函数的返回值。
    可以调用函数并返回值这一事实意味着您的函数的签名很好。
    您提供的句柄无效,或者您的 Size2D 参数超出范围。 因为您正在传递maxint,所以我认为您在这里碰运气。

    Size2D 中传递一些更合理的内容。

    size2D.S32X := 100;
    size2D.S32Y := 100;
    ret := is_AOI(cam, IS_AOI_IMAGE_SET_SIZE, size2D, SizeOf(size2D));
    

    【讨论】:

    • 我进行了更改,但仍然是 125。这是一个 32 位应用程序。
    • 有效!我还必须更改调用其他函数的顺序。谢谢。
    • @johan 问题中的代码是准确的。为什么你认为void* 没有映射到Pointer
    • 那么,这是如何处理这个问题的。此外,您对调用约定的理解也不完全正确。或者你的解释很薄弱。在 x64 中只有一种调用约定。所以cdeclstdcall 等就被忽略了。习惯用法是包含cdecl 用于针对x86,并让x64 编译器忽略它。在某种逻辑意义上,函数的调用约定确实是cdecl,但恰好在 x64 上,它的实现与所有其他约定相同。
    • 它确实映射到指针,var 更优雅,注意我说“你可以用无类型的 var 参数替换 *void。”,不是你应该或你必须。我已经消除了第一行的歧义。
    【解决方案2】:

    您现有的代码是对本机代码的完美翻译。在 C++ 中,void* 是一个无类型指针。 Delphi 中的等价类型是Pointer。换句话说,您已经正确翻译了该参数。

    我唯一能发现不正确的是HIDS 可能是一个指针大小的整数。所以它可能应该被声明为UIntPtr,如果你使用的是支持该类型的现代Delphi。但是,我希望您的代码是 32 位的,所以这对您来说可能不是问题。

    所以结论是你的标题翻译是足够的,并且你确实传递了无效的参数。您的问题的解决方案需要您研究库的文档,并确保您以正确的顺序调用所有必需的函数,并使用正确的参数。

    【讨论】:

    • 参数确实是主要问题,但是,使用 UIntPtr(起初是 THandle)而不是 Cardinal 用于 HIDS 似乎也有助于同一头文件的其他功能。并且使用 untyped var 而不是 Pointer 使代码更易于阅读。无论如何:这个问题已经解决了!
    • 如果您的代码是 32 位,则 UIntPtr 与 Cardinal 相同。无类型参数也可以。如果你需要传递 nil,那就麻烦了。
    猜你喜欢
    • 2023-04-05
    • 2018-04-19
    • 1970-01-01
    • 1970-01-01
    • 2013-05-21
    • 1970-01-01
    • 1970-01-01
    • 2010-09-29
    • 2013-07-19
    相关资源
    最近更新 更多