(Delphi)使用函数指针参数调用DLL [英] (Delphi) Call DLL with function pointer parameter

查看:244
本文介绍了(Delphi)使用函数指针参数调用DLL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

调用外部DLL并传递一个函数(指针)作为参数。
我最近有不同的问题,传递一些参数到DLL,你帮助。
希望有人知道如何做到这一点....



这里是需要从Delphi调用的DLL(cpp)中的函数声明: / p>

 

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

externCexport_dll_function void SetAllocateFunction(PTR_Allocate);
externCexport_dll_function void SetDeallocateFunction(PTR_Deallocate);

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

void取消分配(char * buffer)
{
delete [] buffer;
}

可以请你帮我一下, Delphi(7)?



这是我试过的,它会抛出异常(外部异常):

 

type
PByte = ^ TByte;
TByte =字节数组;
TFunc = function(var pbuffer:PByte; var psize:Cardinal):integer; cdecl;
过程_SetAllocateFunction(var f:TFunc); cdecl;

实现

函数分配(var pbuffer:PByte; var psize:Cardinal):整数; cdecl;
begin
psize:= psize * 2;
GetMem(pbuffer,psize);
结束

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

非常感谢!

解决方案

如果您不确定自己在做什么,始终以最多的文字开头。函数原型表示它接收到一个指向char的指针的指针,这就是您应该使用的:

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

一旦你确定是正确的,那么然后开始用他们的更像德尔福般的等同物。如果你跳过这个第一步,你可能永远都不会这样做,因为你会继续改变一些开始错误的东西。



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

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

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

 键入
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版本声明一个指针到字节的类型,所以使用它:

 键入
PTR_Allocate = procedure param1:PByte; var param2:LongWord); cdecl;






现在开始 SetAllocateFunction 。它说它收到一个 PTR_Allocate 参数,它是一个指向函数的指针。 Delphi的过程类型是隐式的指针,所以我们上面声明的类型已经完全适合Delphi的等效。不要使用额外的var指令通过引用,否则您将遇到问题,甚至在程序尝试分配任何内存之前。这是其他答案被忽略的东西。

 程序SetAllocateFunction(param:PTR_Allocate); cdecl; 

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

  SetAllocateFunction; extern'foo.dll'name'_SetAllocateFunction'; 






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

  procedure分配(out pbuffer:PByte; var psize:LongWord; cdecl; 
begin
psize:= psize * 2;
GetMem(pbuffer,psize);
结束;

您可以使用之前的功能设置它:

  SetAllocateFunction(Allocate); 

通知我不需要一个单独的变量,我没有使用 @ 操作符,如果你需要使用 @ 运算符提到一个函数指针,在大多数案例中,你做错了,你通常不需要它,使用该操作符可以在程序中隐藏错误,例如签名不匹配,因为默认设置是 @ 操作符被 ,使用它从函数指针中删除类型, d无类型的指针与Delphi中的所有内容兼容,因此它们适合任何其他功能指针类型,包括带有错误签名的指针。



只能使用 @ ,当编译器已经指出它已经尝试调用该功能时,例如提到如何没有足够的参数或提及函数的返回类型。


I'm stuck with calling an external DLL and passing a function (pointer) as parameter. I've recently had different problem of passing some arguments to DLL and you helped. Hope, someone know how to do this as well....

Here's function declaration in DLL (cpp) that needs to be called from Delphi:


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;
}

Could you please be so kind to help me rewrite this in Delphi (7) ?

Here's what I've tried and it throws an exception ("External exception"):


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);   

Thank you very much !

解决方案

If you're not sure what you're doing, always start with the most literal translation. The function prototype says it receives a pointer to a pointer to a char, so that's what you should use:

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

Once you're sure it's right, then start replacing things with their more Delphi-like equivalents. If you skip this first step, you might never get it right because you'll just keep making changes to something that started out wrong.

So, are you sure the above is right? Not quite. Char in Delphi can have different meanings depending on the product version. You're using Delphi 7, but you might upgrade, so you might share this code with someone else, so you should be explicit about what size Char you want. Use AnsiChar when you need a one-byte type.

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

Now we can start making it look more like Delphi. One level of pointer parameter can be replaced with a "var" or "out" directive. Do that to each parameter:

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

Pointer-to-AnsiChar is such a common type that Delphi already has a name for it: PAnsiChar. Use the idiomatic name:

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

And finally, you might wish to take some liberty with the whole notion that there are characters involved at all. You're clearly allocating memory for arbitrary byte buffers, so Byte is probably a better choice than any character type. Recent Delphi versions declare a pointer-to-byte type, so use that:

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


Now on to SetAllocateFunction. It says it receives a PTR_Allocate parameter, which is a pointer to a function. Delphi's procedure types are implicitly pointers, so the type we've declared above is already exactly right for the Delphi equivalent. Don't pass it by reference with an extra "var" directive or you will have the problems you've seen, even before your program attempts to allocate any memory. This is something the other answers have overlooked.

procedure SetAllocateFunction(param: PTR_Allocate); cdecl;

Don't add an underscore to the start of the name, either, unless you want to make it inconvenient to call in your own code. If it's exported from the DLL using a different name, then use a "name" clause when you write the function's implementation:

procedure SetAllocateFunction; extern 'foo.dll' name '_SetAllocateFunction';


Finally, how to implement the allocation function. Start with something that matches the signature for PTR_Allocate, and then go ahead and implement it using as literal a translation as possible from the original C++ code.

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

You can set it with the function from before:

SetAllocateFunction(Allocate);

Notice I didn't need a separate variable and I haven't used the @ operator. If you need to use the @ operator to mention a function pointer, in most cases, you're doing it wrong. You usually don't need it. Using that operator can hide errors in your program, such as signature mismatches, because the default setting is for the @ operator to be untyped. Using it removes the type from the function pointer, and untyped pointers are compatible with everything in Delphi, so they fit with any other function-pointer type, including the ones with wrong signatures.

Only use @ on a function pointer when the compiler has already indicated that it has tried to call the function, such as by mentioning how you don't have enough parameters or by mentioning the function's return type.

这篇关于(Delphi)使用函数指针参数调用DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆