我编了个动态链接库GetCode.dll
库中有个过程为:
procedure loadnode(mytv:TTreeView;label1:Tlabel;iid:integer;Aconn:TAdoConnection);
我在程序中使用静态加载的话,第一次执行正确,第二次就出错
‘Access violation at address .... in module 'GetCode.dll' '
用动态加载的话一执行到调用的过程就出错
是不是不能使用组件作为涵数参数?
有没有谁有这样的例子?

解决方案 »

  1.   

    网上可以搜到很多例子,给你一个:
    Delphi中高级DLL的编写和调用    根据Delphi提供的有关 DLL编写和调用的帮助信息,你可以很快完成一般的 DLL编写和调用的 应用程序。本文介绍的主题是如何编写和调用能够传递各种参数(包括对象实例)的 DLL。例如, 主叫程序传递给 DLL一个ADOConnection 对象示例作为参数, DLL中的函数和过程调用通过该对象 实例访问数据库。  需要明确一些基本概念。对于 DLL,需要在主程序中包含 exports子句,用于向外界提供调用 接口,子句中就是一系列函数或过程的名字。对于主叫方(调用 DLL的应用程序或其它的 DLL), 则需要在调用之前进行外部声明,即external保留字指示的声明。这些是编写 DLL和调用 DLL必须 具备的要素。  另外需要了解Object Pascal 中有关调用协议的内容。在Object Pascal 中,对于过程和函数 有以下五种调用协议:  指示字 参数传递顺序 参数清除者 参数是否使用寄存器
      register 自左向右 被调例程 是
      pascal 自左向右 被调例程 否
      cdecl 自右向左 调用者 否
      stdcall 自右向左 被调例程 否
      safecall 自右向左 被调例程 否  这里的指示字就是在声明函数或过程时附加在例程标题之后的保留字,默认为register,即是 唯一使用 CPU寄存器的参数传递方式,也是传递速度最快的方式;  pascal: 调用协议仅用于向后兼容,即向旧的版本兼容;
      cdecl: 多用于 C和 C++语言编写的例程,也用于需要由调用者清除参数的例程;
      stdcall: 和safecall主要用于调用Windows API 函数;其中safecall还用于双重接口。
      在本例中,将使用调用协议cdecl ,因为被调用的 DLL中,使用的数据库连接是由主叫方传递 得到的,并且需要由主叫方处理连接的关闭和销毁。  下面是 DLL完整源程序和主叫程序完整源程序。包括以下四个文件:   Project1.DPR {主叫程序}
       Unit1.PAS {主叫程序单元}
       Project2.DPR {DLL}
       Unit2.PAS {DLL单元}
      {---------- DLL 主程序 Project2.DPR ----------}  library Project2;  uses
       SysUtils,
       Classes,
       Unit2 in ‘Unit2.pas‘ {Form1};  {$R *.RES}  { 下面的语句用于向调用该 DLL的程序提供调用接口 }
      exports
       DoTest; { 过程来自单元Unit2 }  begin
      end.
    {---------- DLL中的单元 Unit2.PAS ----------}  unit Unit2;  interface  uses
       Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
       Db, ADODB, StdCtrls, Menus;  type
       TForm1 = class(TForm)
       ADOConnection1: TADOConnection;{ 本地数据库连接 }
       Memo1: TMemo; { 用于显示信息 }
       private
       public
       end;  { 该过程向外提供 }
      procedure DoTest(H: THandle; { 获得调用者的句柄 }
       AConn: TADOConnection;{ 获得调用者的数据库连接 }
       S: string; { 获得一些文本信息 }
       N: Integer); { 获得一些数值信息 }
       cdecl; { 指定调用协议 }  implementation  {$R *.DFM}  procedure DoTest(H: THandle; AConn: TADOConnection; S: string; N: Integer);
      begin
       Application.Handle := H; { 将过程的句柄赋值为调用者的句柄 }
       { 上面语句的作用在于, DLL的句柄和调用者的句柄相同,在任务栏中就不会 }
       { 各自出现一个任务标题了。 }
       with TForm1.Create(Application) do try{ 创建窗体 }
       Memo1.Lines.Append(‘成功调用‘); { 显示一行信息 }
       ADOConnection1 := AConn; { 获得数据库连接的实例 }
       Memo1.Lines.Append(
       ADOConnection1.ConnectionString +
       ‘ - ‘ + S + ‘ - ‘ + IntToStr(N)); { 根据得到的参数显示另一行信息 }
       ShowModal; { 模式化显示窗体 }
       finally
       Free; { 调用结束时销毁窗口 }
       end;
      end;  end.
      {---------- 调用者 Project1.DPR,很普通的工程文件 ----------}  program Project1;  uses
    Forms,
       Unit1 in ‘Unit1.pas‘ {Form1};  {$R *.RES}  begin
       Application.Initialize;
       Application.CreateForm(TForm1, Form1);
       Application.Run;
      end.
      {---------- 调用者单元Unit1.PAS ----------}  unit Unit1;  interface  uses
       Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
       StdCtrls, Db, ADODB;  type
       TForm1 = class(TForm)
       Button1: TButton; { 按此按钮进行调用 }
       ADOConnection1: TADOConnection; { 本地数据库连接,将传递给 DLL }
       procedure Button1Click(Sender: TObject);{ 调用 DLL}
       private
       public
       end;  var
       Form1: TForm1;  implementation  {$R *.DFM}  { 外部声明必须和 DLL中的参数列表一致,否则会运行时错误 }
      procedure DoTest(H: THandle; { 传递句柄 }
       AConn: TADOConnection; { 传递数据库连接 }
       S: string; { 传递文本信息 }
       N: Integer); { 传递数值信息 }
       cdecl; { 指定调用协议 }
       external ‘Project2.dll‘;{ 指定过程来源 }  { 调用过程 }
      procedure TForm1.Button1Click(Sender: TObject);
      begin
       DoTest(Application.Handle,
       ADOConnection1,
       ‘Call OK‘,
       256);
      end;  end.
      

  2.   

    procedure loadnode 后面加stdcall了吗?