在网上搜索了很多示例,都重复,也不怎么令人满意。
哪位自己做过的?可以发示例给我吗?分数最多给解决问题者,只给一到两个人。email:[email protected]

解决方案 »

  1.   

    来自:阿朱, 时间:2001-5-18 8:49:00 [显示:小字体 | 大字体]  
    用Delphi制作DLL
    一 Dll的制作一般步骤
    二 参数传递
    三 DLL的初始化和退出清理[如果需要初始化和退出清理]
    四 全局变量的使用
    五 调用静态载入
    六 调用动态载入
    七 在DLL建立一个TForM
    八 在DLL中建立一个TMDIChildForM
    九 示例:
    十 Delphi制作的Dll与其他语言的混合编程中常遇问题:
    十一 相关资料一 Dll的制作一般分为以下几步:
    1 在一个DLL工程里写一个过程或函数
    2 写一个Exports关键字,在其下写过程的名称。不用写参数和调用后缀。
    二 参数传递
    1 参数类型最好与window C++的参数类型一致。不要用DELPHI的数据类型。
    2 最好有返回值[即使是一个过程],来报出调用成功或失败,或状态。成功或失败的返回值最好为1[成功]或0[失败].一句话,与windows c++兼容。
    3 用stdcall声明后缀。
    4 最好大小写敏感。
    5 无须用far调用后缀,那只是为了与windows 16位程序兼容。三 DLL的初始化和退出清理[如果需要初始化和退出清理]
    1 DLLProc[SysUtils单元的一个Pointer]是DLL的入口。在此你可用你的函数替换了它的入口。但你的函数必须符合以下要求[其实就是一个回调函数]。如下:
    procedure DllEnterPoint(dwReason: DWORD);far;stdcall;
    dwReason参数有四种类型:
    DLL_PROCESS_ATTACH:进程进入时
    DLL_PROCESS_DETACH进程退出时
    DLL_THREAD_ATTACH 线程进入时
    DLL_THREAD_DETACH 线程退出时
    在初始化部分写:
      DLLProc := @DLLEnterPoint;
      DllEnterPoint(DLL_PROCESS_ATTACH);
    2 如Form上有TdcomConnection组件,就Uses Activex,在初始化时写一句CoInitialize (nil);
    3 在退出时一定保证DcomConnection.Connected := False,并且数据集已关闭。否则报地址错。四 全局变量的使用
    在widnows 32位程序中,两个应用程序的地址空间是相互没有联系的。虽然DLL在内存中是一份,但变量是在各进程的地址空间中,因此你不能借助dll的全局变量来达到两个应用程序间的数据传递,除非你用内存映像文件。五 调用静态载入
    1 客户端函数声名:
    1)大小写敏感。
    2)与DLL中的声明一样。
       如: showform(form:Tform);Far;external'yproject_dll.dll';
    3)调用时传过去的参数类型最好也与windows c++一样。
    4)调用时DLL必须在windows搜索路径中,顺序是:当前目录;Path路径;windows;widows\system;windows\ssystem32;六 调用动态载入
    1 建立一种过程类型[如果你对过程类型的变量只是一个指针的本质清楚的话,你就知道是怎么回事了]。如:
    type
       mypointer=procedure(form:Tform);Far;external;
    var
      Hinst:Thandle;
      showform:mypointer;
    begin
       Hinst:=loadlibrary('yproject_dll');//Load一个Dll,按文件名找。
      showform:=getprocaddress(Hinst,'showform');//按函数名找,大小写敏感。如果你知道自动化对象的本质就清楚了。
      showform(application.mainform);//找到函数入口指针就调用。
      Freelibrary(Hinst);
    end;七 在DLL建立一个TForM
    1 把你的Form Uses到Dll中,你的Form用到的关联的单元也要Uses进来[这是最麻烦的一点,因为你的Form或许Uses了许多特殊的单元或函数]
    2 传递一个Application参数,用它建立Form.八 在DLL中建立一个TMDIChildForM
    1 Dll中的MDIForm.FormStyle不用为fmMDIChild.
    2 在CreateForm后写以下两句:
    function ShowForm(mainForm:TForm):integer;stdcall
    var
      Form1: TForm1;
      ptr:PLongInt;
    begin
      ptr:=@(Application.MainForm);//先把dll的MainForm句柄保存起来,也无须释放,只不过是替换一下
      ptr^:=LongInt(mainForm);//用主调程序的mainForm替换DLL的MainForm。MainForm是特殊的WINDOW,它专门管理Application中的Forms资源.
    //为什么不直接Application.MainForm := mainForm,因为Application.MainForm是只读属性
      Form1:=TForm1.Create(mainForm);//用参数建立
    end;
    备注:参数是主调程序的Application.MainForm九 示例:
    DLL源代码:
    library Project2;uses
      SysUtils,
      Classes,
      Dialogs,
      Forms,
      Unit2 in 'Unit2.pas' {Form2};{$R *.RES}
    var
      ccc: Pchar;procedure OpenForm(mainForm:TForm);stdcall;
    var
      Form1: TForm1;
      ptr:PLongInt;
    begin
      ptr:=@(Application.MainForm);
      ptr^:=LongInt(mainForm);
      Form1:=TForm1.Create(mainForm);
    end;procedure InputCCC(Text: Pchar);stdcall;
    begin
      ccc := Text;
    end;procedure ShowCCC;stdcall;
    begin
      ShowMessage(String(ccc));
    end;exports
      OpenForm;
      InputCCC,
      ShowCCC;
    begin
    end.调用方源代码:
    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        Edit1: TEdit;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.DFM}
    procedure OpenForm(mainForm:TForm);stdcall;External'project2.dll';
    procedure ShowCCC;stdcall;External'project2.dll';
    procedure InputCCC(Text: Pchar);stdcall;External'project2.dll';procedure TForm1.Button1Click(Sender: TObject);
    var
      Text: Pchar;
    begin
      Text := Pchar(Edit1.Text);
    //  OpenForm(Application.MainForm);//为了调MDICHILD
      InputCCC(Text);//为了实验DLL中的全局变量是否在各个应用程序间共享
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
      ShowCCC;//这里表明WINDOWS 32位应用程序DLL中的全局变量也是在应用程序地址空间中,16位应用程序或许不同,没有做实验。
    end;十 Delphi制作的Dll与其他语言的混合编程中常遇问题:
    1 与PowerBuilder混合编程
      在定义不定长动态数组方面在函数退出清理堆栈时老出现不可重现的地址错,原因未明,大概与PB的编译器原理有关,即使PB编译成二进制代码也如此。
     
      

  2.   

    呵呵,那你也够懒的,上面的东西够你做各种dll出来了
      

  3.   

    TShowRepXml = function(AHandle: THandle; XmlFileName, RepName:String):TModalResult;
    在TYPE下面定义一个函数对象,包含你要动态调用的DLL里面的参数和返回值procedure TForm1.Button2Click(Sender: TObject);
    var
      LibH:THandle;
      ShowRep:TShowRepXml;                //声明的函数变量
    begin
      t1.SaveToFile('F:\xml²âÊÔ\aaa.xml');
      LibH:= LoadLibrary('E:\GetReport\GetRep.dll');  //获得库的指针
      try
        if Libh = 0 then
        begin
          ShowMessage('tuichu');
          Exit;
        end;
        @ShowRep:= GetProcAddress(LibH,'ShowRepXml');  //取得要执行的函数,ShowRepXml是发布的函数名
        if not (@ShowRep = nil) then
        begin
          ShowRep(Application.Handle,'e:\Patients.xml','234');
        end;
      finally
        FreeLibrary(LibH);
      end;
    end;
    再不懂我也就没办法了。
      

  4.   

    先声明 Tyourpro=procedure;
           var
              yourpro:Tyourpro;
    使用:
    Phandl:=loadlibrary('your_dll.dll');//Load一个Dll,按文件名找。
    @yourpro:=getprocaddress(Phandl,'yourpro');//按函数名找,
    Tyourpro(yourpro);//找到函数入口指针就调用。
    Freelibrary(Phandl);
    [ok]最好用try ..finally..end
      

  5.   

    type
       YouDll=procedure(xobject:TObject);external;
    var
      Hinst:Thandle;
      youpointer:pointer;
    begin
       Hinst:=loadlibrary('youdll.dll');
       @youpointer:=getprocaddress(Hinst,'showform');
       if youpointer<>0 then
       begin
       end;
       Freelibrary(Hinst);
    end;
    大概是这样,没有环境,不能试。
      

  6.   


    楼上的这部分,我也类似地做过,
    LibH:= LoadLibrary('E:\GetReport\GetRep.dll');  //获得库的指针
      try
        if Libh = 0 then
        begin
          ShowMessage('tuichu');
          Exit;
        end;
        @ShowRep:= GetProcAddress(LibH,'ShowRepXml');  //取得要执行的函数,ShowRepXml是发布的函数名
        if not (@ShowRep = nil) then
        begin
          ShowRep(Application.Handle,'e:\Patients.xml','234');
        end;
      finally
        FreeLibrary(LibH);
      end;为什么执行到
    if not (@ShowRep = nil) then
        begin
          ShowRep(Application.Handle,'e:\Patients.xml','234');
        end;
    的时候,我的程序总是不执行      ShowRep(Application.Handle,'e:\Patients.xml','234');
    是什么原因?
      

  7.   

    楼上的(塑料树)这部分,我也类似地做过,
    ///////////////////////////////////////////////
    LibH:= LoadLibrary('E:\GetReport\GetRep.dll');  //获得库的指针
      try
        if Libh = 0 then
        begin
          ShowMessage('tuichu');
          Exit;
        end;
        @ShowRep:= GetProcAddress(LibH,'ShowRepXml');  //取得要执行的函数,ShowRepXml是发布的函数名
        if not (@ShowRep = nil) then
        begin
          ShowRep(Application.Handle,'e:\Patients.xml','234');
        end;
      finally
        FreeLibrary(LibH);
      end;
    /////////////////////////////////////////////////
    为什么执行到
    ////////////////////
    if not (@ShowRep = nil) then
        begin
          ShowRep(Application.Handle,'e:\Patients.xml','234');
        end;
    /////////////////////
    的时候,我的程序总是不执行
    ////////////
          ShowRep(Application.Handle,'e:\Patients.xml','234');
    ////////////////
    是什么原因?
      

  8.   

    我到自己作过一个DLL。不过所谓的动态调用你自己看看。应该不难。其实是一人applicaton.handle的传递问题。窗体有模式与非模式之分。我传一个DLL和一个静态的调用。还有一个DLL的回调函数给你看看。所谓动态就是一个地址取址问题。你自己理解了,不要企图人家给一个完全合符自己使用环境的东西,因为哪样你也得不到好东东了。对不?
    一、DLL的窗口。library DLLpassPro;{ Important note about DLL memory management: ShareMem must be the
      first unit in your library's USES clause AND your project's (select
      Project-View Source) USES clause if your DLL exports any procedures or
      functions that pass strings as parameters or function results. This
      applies to all strings passed to and from your DLL--even those that
      are nested in records and classes. ShareMem is the interface unit to
      the BORLNDMM.DLL shared memory manager, which must be deployed along
      with your DLL. To avoid using BORLNDMM.DLL, pass string information
      using PChar or ShortString parameters. }uses
      SysUtils,
      Classes,
      DLLPass in 'DLLPass.pas' {Form1};{$R *.res}
    exports
      OutDll,
      CloseDLLWindows,
      TestDLLRe;
    begin
    end.
    //这是我以前写的写的,好久了,原来发来的。EXPORTS有三个:
    OUTDLL是窗子的建立。
    CLOSE是关闭和句柄释放
    TESTDLLRE是回调。这个是一个简单的回显,不过你可以作为参考unit DLLPass;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ExtCtrls, ComCtrls;type
      Tfunct = function (iCo: integer):LongInt;stdcall;
      UserMessage = packed record
        UseName: string[80];
        UsePass: string[11];
      end;
      TForm1 = class(TForm)
        Label1: TLabel;
        ComboBox1: TComboBox;
        Label2: TLabel;
        Edit1: TEdit;
        Button1: TButton;
        Label3: TLabel;
        Timer1: TTimer;
        Label4: TLabel;
        procedure Timer1Timer(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
      UserMesRec: array of UserMessage;  //住处数组
      UserString: TStrings;        //相关的唯一信息
      UserCurTime: integer;       //记时变量
      bResult: Boolean;
      bCheck: Boolean;  procedure ReadPassFile();    { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;
      FormInt: LongInt; //用来存贮窗口信息
      iCountP: Integer;  function OutDll(AHandle: THandle):Longint;stdcall;
      procedure CloseDLLWindows(AFormRef: Longint);stdcall;
      procedure TestDLLRe(iCount: integer; Aproc: TFarProc);stdcall;  
    implementation
    {$R *.dfm}function OutDll(AHandle: THandle):Longint;
    Var
      Form1: TForm1;
    begin  Application.Handle := AHandle;
      Form1 := TForm1.Create(Application);
      FormInt := LongInt(Form1);
      //创建窗口
      Form1.Timer1.Enabled := True;
      //开始记数
      Form1.ShowModal;
      Form1.ReadPassFile;
      if Form1.bResult = False then  Result := 0
      else
      Result := FormInt;
      Form1.Free;end;procedure CloseDLLWindows(AFormRef: Longint);
    begin
      if AFormRef > 0 then
         TForm1(AFormRef).Release;   //销毁窗口
    end;
    procedure TestDLLRe(iCount: integer; Aproc: TFarProc);
    var
    i: integer;
    begin
    for i := 0 to 99 do
    begin
      inc(iCountP);  sleep(100);  if Aproc <> nil then
         Tfunct(Aproc)(iCountP);
     end;
    end;
    procedure TForm1.ReadPassFile;
    var
      strEdit: string;
    begin
      strEdit := Edit1.Text;
      bResult := False;
      case ComboBox1.ItemIndex of
       0:
         if strEdit = '7411272'then  bResult := True;
       1 :
         if strEdit = 'Police' then  bResult := True;
       2:
         if strEdit = 'admi' then  bResult := True;
       3:
         if strEdit = '123456' then  bResult := True;
      else
       // showmessage('你输入的用户名有误!请联系管理人员!');
       end;
    end;procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      inc (UserCurTime);
      if UserCurTime >= 10 then
      begin
        UserCurTime := 0 ;
        close;
      end;
    end;procedure TForm1.Button1Click(Sender: TObject);
    var
      strEdit :string;
    begin
      ReadPassFile;
      if bResult = False then
      begin
        Form1.Free;
        Close;
        MessageDlg ('密码或用户名出错!', mtConfirmation , [mbYes] , 0);
      end;
      Label3.Font.Color := clBlue;
      Label3.Caption := '密码正确,正在调入数据库,请稍候.....';
      UserCurTime := 8;end;procedure TForm1.FormCreate(Sender: TObject);
    begin
     ComboBox1.Text := ComboBox1.Items[3];
     ComboBox1.ItemIndex := 3;
    end;end.
    //作用就是对输入的东西进行对比了。很简单的,慢慢看看。下面是调用:unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ComCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        ProgressBar1: TProgressBar;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;
      function OutDll(AHandle: THandle):Longint;stdcall;external 'F:\zhanjiajun\book\程序资料\Delphi Code\校验码\Bin\DLLpassPro.dll'
      procedure CloseDLLWindows(AFormRef: Longint);stdcall;external 'F:\zhanjiajun\book\程序资料\Delphi Code\校验码\Bin\DLLpassPro.dll'
      function FrmGetDLL(iCon: integer):Longint;stdcall;
      procedure TestDLLRe(iCount: integer; Aproc: TFarProc);stdcall; external 'F:\zhanjiajun\book\程序资料\Delphi Code\校验码\Bin\DLLpassPro.dll'
    //静态的。你可以改的。implementation
    {$R *.dfm}
    function FrmGetDLL(iCon: integer):Longint;
    begin
        Form1.ProgressBar1.Position := iCon;
    end;procedure TForm1.Button1Click(Sender: TObject);
    var
      test: Longint;
    begin  test := OutDll(Application.Handle);
      showmessage(IntToStr(test));end;procedure TForm1.Button2Click(Sender: TObject);
    begin
       TestDLLRe(123, @FrmGetDLL);//这个是回调。
    end;end.
    还不清楚就加我QQ:52258388
      

  9.   

    看看是不是unicode的原因,用dependence等看看,或者如果知道函数序号/地址的话,直接调用
      

  10.   

    你在DLL里面要调用的函数要EXPORTS啊,不然怎么找的到啊
      

  11.   

    我这个都是前两天做一个DLL的时候做的测试程序,绝对没有问题的,你如果不行,首先看看自己写的DLL有没有发布函数,然后看看申请的DLL的handle是不是0,然后看函数指针是不是为空。然后……大概没有然后了吧,就这些东西啊!
      

  12.   

    函数指针不为空,大概是179XXXX吧,我当然要exports了
      

  13.   

    Loadlibrary就可以
    Google上N多的
      

  14.   

    那就奇怪了,我的代码绝对可以执行的啊,上个星期我做了两个库,一直都是用这个测试的,不可能错的。楼主仔细看看吧,看看库里面是不是有什么问题。参数写对没有,还有,如果库里面显示模式窗口,要把APPLICATION的句柄传过去。还有什么?我也不知道了。