本贴承接贴:http://expert.csdn.net/Expert/topic/2846/2846596.xml?temp=.5552027。由于大家仅仅给出方案,不能将修改方法调试通过,因此这个问题一直没能解决。希望回复此贴的朋友,在给出方案之前,请先调试一下,如果能通过再回复,问题解决立即结贴。
上贴案例:
  程序的目的是通过点击窗体上的按钮调用dll文件,通过dll的过程SetActiveLanguage将按钮的caption变为按钮1,但是当在dll过程SetActiveLanguage()里设置form1.Button1.Caption:='按钮1';时需要将form1.button传递给dll。由于已经uses Unit1 in 'Unit1.pas',//引用Unit1.pas ,所以本以为能够成功,没想到运行时出错,出现Access Violation address 0028332E in moudle 'Project2.dll',Read address 00000324错误,把Form1的成员对象(button1)传递给dll出错。
////////////////////////////
主工程文件
Project1.dprprogram Project1;uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};{$R *.res}begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
//////////////////////////////////////////
主单元文件Unit1.pas
unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls;
//调用project2.dll文件里的过程SetActiveLanguage
procedure SetActiveLanguage(LanguageName:string);export;stdcall;external 'project2.dll';type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
  //调用过程
  SetActiveLanguage('');
end;end.
//////////////////
编译生成dll文件的工程文件project2.dpr,它引用了Unit1.pas里的按钮对象button1.library Project2;
uses
  SysUtils,
  Unit1 in 'Unit1.pas',//引用Unit1.pas
  Classes;
{$R *.res}procedure SetActiveLanguage(LanguageName:string);export; stdcall;
begin
  //处理Unit1.pas里form1类中的按钮对象
  form1.Button1.Caption:='按钮1';
end;exports
 SetActiveLanguage;
begin
end.
///////////////////////////////////////////////
以下是不用dll实现该功能的方案
不使用dll,而是使用另一个与之无关的单元文件,就可以解决问题。请看如下代码:
Project1.dprprogram Project1;uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2};{$R *.res}begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
//////////////////////////////////////////////////
Unit1.pasunit Unit1;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,unit2;type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
  form2.SetActiveLanguage('ddd');
end;end.
///////////////////////////////////////////
Unit2.pasunit Unit2;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;type
  TForm2 = class(TForm)
  procedure SetActiveLanguage(LanguageName:string);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form2: TForm2;implementation
uses unit1;
{$R *.dfm}
 procedure TForm2.SetActiveLanguage(LanguageName:string);
begin
  //处理Unit1.pas里form1类中的按钮对象
  form1.Button1.Caption:='按钮1';
end;
end.
////////////////////////////////////////////////////////////////
网友提出来的问题和解决方案(但是都不能调试通过)
aiirii(ari-爱的眼睛) ( ) 信誉:181---------------------〉 
在兩個程序中, 都加入uses ShareMem;
>>form1.Button1.Caption:='按钮1';
如果你是指主程序的Form1, 那你這種思路是有問題的!
dll與主程序, 是無法這樣簡單共享對象的!
你應該將 主程序的 Button1.handle 傳進來, 然後用sendMessage(handle, ...., BE_Click, nil);
類似這樣的操作, 發送個按鈕點擊消息!!
 Shince() ( ) 信誉:100 -----------------〉
SetActiveLanguage 里的Form1在project1.exe运行是是一个未被初始化的对象,所以会出现这个异常。
 在兩個程序中, 都加入
uses ShareMem;在Dll和宿主之间共享一个内存块是一个通用的做法,调用DLL里的函数或过程修改共享内存块里的数据,再在宿主里得到修改后的数据。
如果必须使用dll,可考虑传给 Dll 里的SetActiveLanguage 一个地址引用的变量,在里面修改后在Form1里修改Button.Caption.SetActiveLanguage(LanguageName:string;var str: string); 
...
str := 'abc';
...
hanlin2004(渴死的鱼) ( ) 信誉:100 --------------------〉
把 string 类型改为 ShortStringxhg0418(新手) ( ) 信誉:100 ---------------------------〉
用回调函数如何!
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
希望回复此贴的朋友先调试通过,然后再给出解决方法,并给出完整代码。
谢谢。

解决方案 »

  1.   

    上次我是沒仔細看你的代碼, 現在再看下!
    發覺, 你思路不對!
    代碼錯的很利害!!!dll中 uses unit1;
    也有個Form1變量, 但與你主程序的form1, 根本不是一回事!以後就不用說了, 思路錯了, 代碼就不可能對了
      

  2.   

    如果要想让dll使用主程序的form1,请问应该是什么思路?能不能给出完整代码供参考?
      

  3.   

    unit MainFrm;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;type
      TForm1 = class(TForm)
        btnShowModal: TButton;
        BtnShow: TButton;
        procedure btnShowModalClick(Sender: TObject);
        procedure BtnShowClick(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    //静态引入DLL中的方法
    procedure ShowDLLModalForm(aHandle: THandle); stdcall external '..\5-1\DLLShowForm.dll';
    procedure ShowDLLForm(aHandle: THandle); stdcall external '..\5-1\DLLShowForm.dll';var
      Form1: TForm1;implementation{$R *.dfm}
    //调用DLL里输出的ShowDLLModalForm方法,模式显示窗口
    procedure TForm1.btnShowModalClick(Sender: TObject);
    begin
      ShowDLLModalForm(Application.Handle);
    end;//调用DLL里输出的ShowDLLForm方法,非模式显示函数
    procedure TForm1.BtnShowClick(Sender: TObject);
    begin
      ShowDLLForm(Application.Handle);
    end;end.
    library DLLShowForm;uses
      SysUtils,
      Classes,
      DLLFrm in 'DLLFrm.pas' {frmDLL};
    {$R *.res}
    //输出ShowDLLModalForm,ShowDLLForm接口方法,以便外部程序调用
    exports
      ShowDLLModalForm, ShowDLLForm;
    begin
    end.unit DLLFrm;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;type
      TfrmDLL = class(TForm)
      private
        { Private declarations }
      public
        { Public declarations }
      end;{声明要引出的方法}
    procedure ShowDLLModalForm(aHandle: THandle); stdcall; //模式显示窗口
    procedure ShowDLLForm(aHandle: THandle); stdcall; //非模式显示窗口implementation{$R *.dfm}//模式显示窗口
    procedure ShowDLLModalForm(aHandle: THandle);
    begin
      Application.Handle := aHandle; //传递应用程序句柄
      with TfrmDLL.Create(Application) do //创建窗体
      begin
        try
          ShowModal; //模式显示窗体
        finally
          free;
        end;
      end;
    end;
    //非模式显示窗口
    procedure ShowDLLForm(aHandle: THandle);
    begin
      Application.Handle := aHandle; //传递应用程序句柄
      with TfrmDLL.Create(application) do //创建窗体
        Show; //非模式显示窗体
    end;
    end.这是一个怎么使用的例子,发给你看看