gpt4 book ai didi

delphi - (Delphi) 用函数指针参数调用DLL

转载 作者:行者123 更新时间:2023-12-03 15:18:54 29 4
gpt4 key购买 nike

我一直坚持调用外部 DLL 并传递函数(指针)作为参数。我最近在向 DLL 传递一些参数时遇到了不同的问题,你提供了帮助。希望,有人也知道如何做到这一点......

下面是需要从 Delphi 调用的 DLL (cpp) 中的函数声明:


typedef void (*PTR_Allocate)(char**, unsigned long*);
typedef void (*PTR_Deallocate)(char*);

extern "C" export_dll_function void SetAllocateFunction(PTR_Allocate);
extern "C" export_dll_function void SetDeallocateFunction(PTR_Deallocate);

void Allocate(char** pbuffer, unsigned long* psize)
{
*psize = *psize * 2;
*pbuffer = new char[*psize];
}

void Deallocate(char* buffer)
{
delete[] buffer;
}

您能帮我用 Delphi (7) 重写这个吗?

这是我尝试过的方法,它引发了异常(“外部异常”):


type
PByte = ^TByte;
TByte = array of byte;
TFunc = function(var pbuffer: PByte; var psize: Cardinal): integer; cdecl;
Procedure _SetAllocateFunction(var f: TFunc); cdecl;

implementation

function Allocate(var pbuffer: PByte; var psize: Cardinal): Integer; cdecl;
begin
psize := psize * 2;
GetMem(pbuffer, psize);
end;

var Func: TFunc;
Func := @Allocate;
_SetAllocateFunction(Func);

非常感谢!

最佳答案

如果您不确定自己在做什么,请始终从最直白的翻译开始。函数原型(prototype)表示它接收一个指向 char 的指针,所以这就是您应该使用的:

type
PTR_Allocate = procedure(param1: ^^Char; param2: ^LongWord); cdecl;

一旦您确定它是正确的,然后开始用更类似于 Delphi 的等效项替换内容。如果您跳过第一步,您可能永远不会做对,因为您只会不断地对开始时错误的内容进行更改。

那么,您确定以上内容正确吗?不完全的。 Delphi 中的 Char 根据产品版本的不同可以有不同的含义。您正在使用 Delphi 7,但您可能会升级,因此您可能会与其他人共享此代码,因此您应该明确您想要的 Char 大小。当您需要一字节类型时,请使用 AnsiChar。

type
PTR_Allocate = procedure(param1: ^^AnsiChar; param2: ^LongWord); cdecl;

现在我们可以开始让它看起来更像 Delphi。一级指针参数可以用“var”或“out”指令替换。对每个参数执行此操作:

type
PTR_Allocate = procedure(out param1: ^AnsiChar; var param2: LongWord); cdecl;

AnsiChar 指针是一种非常常见的类型,Delphi 已经为它起了一个名字:PAnsiChar。使用惯用名称:

type
PTR_Allocate = procedure(out param1: PAnsiChar; var param2: LongWord); cdecl;

最后,您可能希望对涉及角色的整个概念采取一些自由。您显然正在为任意字节缓冲区分配内存,因此 Byte 可能是比任何字符类型更好的选择。最近的 Delphi 版本声明了一个指向字节类型的指针,因此使用它:

type
PTR_Allocate = procedure(out param1: PByte; var param2: LongWord); cdecl;
<小时/>

现在进入SetAllocateFunction。它说它接收一个PTR_Allocate参数,它是一个指向函数的指针。 Delphi 的过程类型是隐式指针,因此我们上面声明的类型对于 Delphi 等效项来说已经完全正确。不要使用额外的“var”指令通过引用传递它,否则即使在程序尝试分配任何内存之前,您也会遇到您所看到的问题。这是其他答案忽略的事情。

procedure SetAllocateFunction(param: PTR_Allocate); cdecl;

也不要在名称开头添加下划线,除非您想让在您自己的代码中调用不方便。如果它使用不同的名称从 DLL 导出,则在编写函数的实现时使用“name”子句:

procedure SetAllocateFunction; extern 'foo.dll' name '_SetAllocateFunction';
<小时/>

最后,如何实现分配功能。从与 PTR_Allocate 签名匹配的内容开始,然后继续使用原始 C++ 代码的尽可能字面的翻译来实现它。

procedure Allocate(out pbuffer: PByte; var psize: LongWord; cdecl;
begin
psize := psize * 2;
GetMem(pbuffer, psize);
end;

可以用之前的函数来设置:

SetAllocateFunction(Allocate);

请注意,我不需要单独的变量,也没有使用 @ 运算符。如果您需要使用 @ 运算符来提及函数指针,在大多数情况下,您就做错了。你通常不需要它。使用该运算符可以隐藏程序中的错误,例如签名不匹配,因为默认设置是@运算符无类型。使用它会从函数指针中删除类型,并且无类型指针与 Delphi 中的所有内容兼容,因此它们适合任何其他函数指针类型,包括签名错误的类型。

仅当编译器已表明它已尝试调用函数时,才在函数指针上使用@,例如通过提及您如何没有足够的参数或通过提及函数的返回类型。

关于delphi - (Delphi) 用函数指针参数调用DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1819180/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com