源代码如下:
library CalendarLib;{CalendarLib.dll}
uses
  ShareMem,
  SysUtils,
  Classes,
  DLLFrm in 'DLLFrm.pas' {DLLForm};
exports
  ShowCalendar;
begin
end.unit DLLFrm;
interface
uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, Grids, Calendar;
type
  TDLLForm = class(TForm)
    calDllCalendar: TCalendar;
    procedure calDllCalendarDblClick(Sender: TObject);
  end;
{ Declare the export function }
function ShowCalendar(AHandle: THandle; ACaption: String): TDateTime; StdCall;
implementation
{$R *.DFM}
function ShowCalendar(AHandle: THandle; ACaption: String): TDateTime;
var
  DLLForm: TDllForm;
begin
  // Copy application handle to DLL's TApplication object
  Application.Handle := AHandle;
  DLLForm := TDLLForm.Create(Application); 
  try
    DLLForm.Caption := ACaption;
    DLLForm.ShowModal;
    Result := DLLForm.calDLLCalendar.CalendarDate; // Pass the date back in Result
  finally
    DLLForm.Free;
  end;
end;procedure TDLLForm.calDllCalendarDblClick(Sender: TObject);
begin
  Close;
end;end.{
Copyright ?1999 by Delphi 5 Developer's Guide - Xavier Pacheco and Steve Teixeira
}unit MainFfm;//调用DLL的程序interfaceuses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls;type
  { First, define a procedural data type, this should reflect the
    procedure that is exported from the DLL. }
  TShowCalendar = function (AHandle: THandle; ACaption: String): TDateTime; StdCall;  { Create a new exception class to reflect a failed DLL load }
  EDLLLoadError = class(Exception);  TMainForm = class(TForm)
    lblDate: TLabel;
    btnGetCalendar: TButton;
    procedure btnGetCalendarClick(Sender: TObject);
  end;var
  MainForm: TMainForm;implementation{$R *.DFM}procedure TMainForm.btnGetCalendarClick(Sender: TObject);
var
  LibHandle   : THandle;
  ShowCalendar: TShowCalendar;
begin  { Attempt to load the DLL }
  LibHandle := LoadLibrary('CALENDARLIB.DLL');
  try
    { If the load failed, LibHandle will be zero.
      If this occurs, raise an exception. }
    if LibHandle = 0 then
      raise EDLLLoadError.Create('Unable to Load DLL');
    { If the code makes it here, the DLL loaded successfully, now obtain
      the link to the DLL's exported function so that it can be called. }
    @ShowCalendar := GetProcAddress(LibHandle, 'ShowCalendar');
    { If the function is imported successfully, then set lblDate.Caption to reflect
      the returned date from the function. Otherwise, show the return raise
      an exception. }
    if not (@ShowCalendar = nil) then
      lblDate.Caption := DateToStr(ShowCalendar(Application.Handle, Caption))
    else
      RaiseLastWin32Error;                                                               
  finally
    FreeLibrary(LibHandle); // Unload the DLL.
    //注:运行此句会出错,将此句注释掉后就正常了。
    //我用的是Delphi6。
  end;
end;end.

解决方案 »

  1.   

    Application.Handle := AHandle;把这一句注释掉
      

  2.   

    to  DelphiBoy2003(我是李逍遥):
      注释后仍然报错。
      

  3.   

    Application.Handle := AHandle;对于模式窗体非要不可。
    在TDLLForm的CLose事件中要让DLLForm的实例Free掉。
    procedure TForm_Main.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      Action:=caFree;
    end;
      

  4.   

    to jifee(杰菲) :
      DLLForm.Free;这条语句会Free掉窗体的。而且用你的方法仍然报错。
    to sywind(来如风):
      因为运行到那句会报错,所以我把那一句注掉了,结果就不报错了,但我不明白是为什么。
      

  5.   

    FreeLibrary(LibHandle); // Unload the DLL.这一句不能不要!!!!
      

  6.   

    function ShowCalendar(AHandle: THandle; ACaption: String): TDateTime;
    var
      DLLForm: TDllForm;
    begin
      // Copy application handle to DLL's TApplication object
      Application.Handle := AHandle;
      DLLForm := TDLLForm.Create(Application); 
      try
        DLLForm.Caption := ACaption;
        DLLForm.ShowModal;
        Result := DLLForm.calDLLCalendar.CalendarDate; // Pass the date back in Result
      finally
        DLLForm.Free;
        application.Handle:= 0; //在DllForm这里加上这一句。
      end;
    end;
      

  7.   

    此书的作者和我们开了个玩笑,书中代码后有一段话:
    警告:如果DLL中的导出函数或过程以字符串或动态数组作为参数或返回值,那么ShareMem必须是DLL和项目的uses子句中的第一单元。这应用于应用程序和DLL的一切字符串的传递,甚至隐含在记录和类中的字符串。ShareMem是共享的内存管理器Borlandmm.dll的接口单元,Borlandmm.dll必须与DLL一起发布。要避免使用Borlandmm.dll,就得用PChar或者ShortString来传递字符串信息。我打开调用DLL的项目代码,居然没有引用SharMem单元,添加进去后就OK了。
      

  8.   

    我试过了,没有出错的。
    D5, D6都试过。FreeLibrary(LibHandle);
    是把打开的库Free掉,你可以Trace到这一句,看看LibHandle是不是变了?
      

  9.   

    按照作者的说法,我把function ShowCalendar(AHandle: THandle; ACaption: String)改为function ShowCalendar(AHandle: THandle; ACaption: PChar),并将DLL和调用DLL的项目中引用的ShareMem单元删除,程序仍然可以正常运行。
      

  10.   

    此句
      DLLForm := TDLLForm.Create(Application); 
    改为
      DLLForm := TDLLForm.Create(nil); 
    好像就可以了。