//公共代码如下:type
  TDllRec = packed record
    cdApplication: TApplication;
    cdHrd: THandle;
    DllFile: PChar;
    DllPro: PChar;
  end;  PDllRec = ^TDllRec;
//主程序调用如下:  //调用统一入口动态库
  vHrd := LoadLibrary('abrk.dll');
  try
    if vHrd <> 0 then
    begin
      @vDllPro := GetProcAddress(vHrd, 'proc');
      if @vDllPro <> nil then
        try
          vDllPro(vDllRec);
        except
          on e:Exception do
            ShowMessage(e.Message);
        end;
    end;
//abrk.dll文件的代码如下:
type
  TProc = procedure (AppHld: THandle);stdcall;procedure proc(vAdy : PDllRec);stdcall;implementation
    
procedure proc(vAdy : PDllRec);stdcall;
var
  vHrd : THandle;
  vDllPro : TProc;
begin
  vHrd := LoadLibrary(PChar(vAdy.DllFile));
  if vHrd<>0 then
     begin
       @vDllPro :=GetProcAddress(vHrd,PChar(vAdy.DllPro));
       if @vDllPro <> nil then
          vDllPro(vAdy.cdHrd);
    end;
end;
exports
  proc;现在的问题是:当我主程序调用跟踪至abrk.dll的时候发现vady.dllfile的值并不是我调用的时候的值,我跟踪调用处时发现vady.dllfile的值是正值的,也是就说调用的时候是正确的,但调用进来的时候发现值发生了变化,不知道这样做是否有问题,还请大家帮忙看下。

解决方案 »

  1.   

    [闽]SAM  不好意思 我不懂这个 [广州]-SOFT
      

  2.   

    你的代码帖的好像不大对.没帖dll的代码
    错误可能是函数的调用方式不对.如果是c++的dll,默认是cedel的.
      

  3.   

    下面就是abrk.dll的代码,这个dll都是使用delphi写的不是C++写的至于调用的方式不对还请指教?还有其它的什么调用方式呢?这里的调用我可以跟踪到abrk.dll中//abrk.dll文件的代码如下:
    type
      TProc = procedure (AppHld: THandle);stdcall;procedure proc(vAdy : PDllRec);stdcall;implementation
        
    procedure proc(vAdy : PDllRec);stdcall;
    var
      vHrd : THandle;
      vDllPro : TProc;
    begin
      vHrd := LoadLibrary(PChar(vAdy.DllFile));
      if vHrd<>0 then
         begin
           @vDllPro :=GetProcAddress(vHrd,PChar(vAdy.DllPro));
           if @vDllPro <> nil then
              vDllPro(vAdy.cdHrd);
        end;
    end;
    exports
      proc;
      

  4.   

    abrk.dll 如下:
    library ABRK;
    uses
      SysUtils,
      Classes,
    Windows,
    forms,
    controls,
    adodb,
      cdConsts in 'pub.pas';{$R *.res}type
      TProc = procedure (AppHld: THandle);stdcall;
        
    procedure proc(vAdy : PDllRec);stdcall;
    var
      vHrd : THandle;
      vDllPro : TProc;
    begin
      vHrd := LoadLibrary(PChar(vAdy.DllFile));
      if vHrd<>0 then
              begin
                @vDllPro :=GetProcAddress(vHrd,PChar(vAdy.DllPro));
                if @vDllPro <> nil then
                  vDllPro(vAdy.cdHrd);
              end;
    end;
    exports
     proc;
    begin
    end.
      

  5.   

    看上面的代码好象没发现什么问题 
    你把你的程序和DLL一起连调 看看到底是哪的错
      

  6.   

    我将程序和DLL一起连调发现,在调用的处发现vdllRec的各个值是正确的,即如下:
     vHrd := LoadLibrary('abrk.dll');
      try
        if vHrd <> 0 then
        begin
          @vDllPro := GetProcAddress(vHrd, 'proc');
          if @vDllPro <> nil then
            try
              vDllPro(vDllRec);
            except
              on e:Exception do
                ShowMessage(e.Message);
            end;
        end;
    可是当我跟踪到abrk.dll中就发现值有问题。可是这个值的传值都是指针传递,类型如下:都是在pub.pas文件中定义的type
      TDllRec = packed record
        cdApplication: TApplication;
        cdHrd: THandle;
        DllFile: PChar;
        DllPro: PChar;
      end;  PDllRec = ^TDllRec;
      

  7.   

    给你贴份
    用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编译成二进制代码也如此。三 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); 
      

  8.   

    to:bob008 你好,谢谢你的分享,我也根据你所写的东西进行了检查,可是我还是找不到什么问题?
      

  9.   

    delphi指针简单入门:   
        
      看一个指针用法的例子:   
      1         var   
      2             X,   Y:   Integer;       //   X   and   Y   整数类型   
      3             P:   ^Integer;           //   P   指向整数类型的指针   
      4         begin   
      5             X   :=17; //   给   X   赋值   
      6             P   :=   @X;                   //   把   x的地址赋给p   
      7             Y   :=   P^;                   //   取出p所指向的数值赋给y   
      8         end;   
        
      第二行定义了两个变量X,y.   第三行声明了p是指向整数类型的指针;意味着p能够指向x或者y的地址.第五行赋给x值,第六行把x的地址赋给p.最   
        
      后通过p指向的变量赋值给y.此时,x和y有相同的值.   
        
      操作符@用来取出变量的地址,也可以取出过程和函数的地址.   
        
      而符号^有两个目标,   
      当它出现在类型定义的前面时如 ^typename 表示指向这种类型的指针;   
      当它出现在指针变量后边时   如 point^ 返回指针指向的变量的值;   
      

  10.   

    b2和b2^不是一个东西,b2是指针,可以说是动态的;b2^是具体保存的内容,是一个地址上保存的实际内容;
      

  11.   

    http://book.77169.org/data/web5304/20050228/20050228__3592290.html
      

  12.   

                @vDllPro :=GetProcAddress(vHrd,PChar(vAdy.DllPro));
                if @vDllPro <> nil then
                  vDllPro(vAdy.cdHrd^);-----+个^号行不
      

  13.   

      vHrd := LoadLibrary(PChar(vAdy.DllFile^));  这里加个^咋样
      if vHrd<>0 then
         begin
           @vDllPro :=GetProcAddress(vHrd,PChar(vAdy.DllPro^));这里也加个咋样
           if @vDllPro <> nil then
              vDllPro(vAdy.cdHrd^); 这里也加个咋样
        end;
      

  14.   

    to:bob008 我根据你提供的技术方案修改了下不是这个问题。但我发现一个意外就是去掉proc函数声明后的stdcall并加上一个freelibraly(vHrd)就可以了.可是我也不知道为什么是这样。