Delphi DLL和Delphi EXE之间的回调功能

5
我正在编写一个Delphi DLL。在这个DLL中,我想要实现一个回调函数,该回调函数应该回调到调用者的Delphi程序。回调函数的主要目的是,在DLL中会发生某些长时间操作,但进度报告(通过进度条)和操作取消应该在调用者的Delphi程序中发生。
我希望得到一些支持,了解如何在DLL中正确实现回调函数。我可以进行下一步分配从EXE传递过来的回调函数,但我不知道如何从DLL本身初始化调用。
以下是定义部分(由EXE和DLL使用):
uses Windows;

Type
  PTCallBackStruct = ^TCallBackStruct;
  TCallBackStruct = packed record
  Handle: THandle;
  Caller: Pointer;           
  FileSize: LongInt;
end;

type

 TFunctionPointerType = function(ZCallbackRec: PTCallBackStruct): Longbool;
  stdcall;

type
  PTDLLParamaters = ^TDLLParamaters;
  TDLLParamaters = packed record
   Handle: THandle;
   Caller: Pointer; 
   CallbackFunction: TFunctionPointerType;
 end;

 var
   DLLCallback: TFunctionPointerType;

EXE文件:

 uses ....    

 type

  function DLL_Callback(ZCallBackRec: PTCallBackStruct): LongBool; stdcall;
    forward;

  implementation

   function DLL_Callback(ZCallBackRec: PTCallBackStruct): LongBool; stdcall;
   begin
      // progress reporting this function should be called back from 
      //the DLL. The Handle and Self parameter should help with identifying 
      // which object initiated the callback
   end; 

通过PTDLL参数从Delphi exe传递给DLL:

// init callback
 DLLParameters := AllocMem(SizeOf(TDLLParamaters));
 with DLLParameters^ do
   begin
     Handle := Application.Handle;
     Caller := Self;
     CallbackFunction:= DLL_Callback;
  end;

加载动态链接库

   .....
   .....

调用DLL
   CompressionCreateLibrary(DLLParameters);
   ....

某些操作

     Free DLL
     ....
     .....
     FreeMem(DLLParameters);

DLL文件:

该函数应该从DLL的特定部分调用,以便向EXE返回与实际操作相关的进度:

   function CallCallBackFromDLL(Size: integer): Integer;
    begin
       //
       .... 
       set up callbackstruct
       .... 
       // calling back
        DLLCallback(CallbackStruct);
      end;

我认为这部分应该没问题:

 // main init call assigning the callback function to the DLL
 function CompressionCreateLibrary(DLLParametersID: PTDLLParamaters): Integer;

 begin

     DLLParametersID.CallbackFunction:= @DLLCallback;

 end;

请帮忙解决DLL中回调函数的正确实现方式,希望能提供一些示例代码。在初始化时进行调试时一切正常,但是回调失败了。谢谢您的帮助。

我不知道你在问什么。有相当多的代码摘录很难拼凑在一起。然后是“回调失败”。那么,失败是什么意思?你的调试有什么结果?请告诉我你已经做了一些调试。其他评论:1. 不要使用 packed。2. 不要使用 @ 来获取过程变量。 - David Heffernan
1
这几乎是一个好问题。您展示了您的代码,并解释了每个部分的作用。您没有包含无关的代码,但显示了所有重要的声明。您没有包括的关键是问题的描述。"失败"不够好。实际发生了什么,您期望发生什么? - Rob Kennedy
更多的注释。没有必要进行堆分配,使用栈中的变量即可。而且传递记录指针是粗糙的。一个记录类型的常量参数肯定是你需要的。 - David Heffernan
亲爱的Rob,亲爱的David,感谢您们的评论。我会尽力进一步解释。我想要一个用于处理tstream内容(基本上是压缩和解压缩)的动态链接库(DLL),DLL应该向调用程序报告进度(已处理的字节数),为了实现这种报告,我想利用回调函数。当我调用 CallCallBackFromDLL 时它只会抛出异常。 - fingomajom
它不仅仅抛出异常,而是抛出一个带有消息的特定类别的异常。你没有告诉我们这个信息,这表明你忽略了它。不要忽略,学会理解并且始终包含这个信息。 - David Heffernan
更多注释:
  1. Application.Handle 不是 THandle。它是 HWND。非常不同。
  2. 如果文件大小大于 4GB,您的设计会崩溃,因为您使用了 32 位整数。
- David Heffernan
1个回答

4

您的赋值语句顺序是错误的。在DLL函数中,DLLParametersID保存了有关回调的信息,但是然后您用全局变量覆盖了它:

DLLParametersID.CallbackFunction:= @DLLCallback;

将它们交换以分配DLLCallback

如果我这样做,会收到编译器错误(实际参数不足)。 - fingomajom
我可以建议您尝试设置断点并逐步执行代码,然后学习查看变量的值。如果您错过了分配的方向,那么您可能会错过其他开发人员认为是显而易见的很多事情!如果您尝试单步执行,也许您可以看到代码运行时真正发生的事情。 - Warren P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接