我想用DLL访问数据库及其表,并返回一个数据集,请帮忙看一下出错原因及解决方法.编译通过,调用时出错.
调用DLL的程序如下:
unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, SUIButton, ExtCtrls, SUIForm, StdCtrls, Buttons, DB, ADODB,
  Grids, DBGrids;type
  TForm1 = class(TForm)
    suiForm1: TsuiForm;
    btnShowForm: TsuiButton;
    Connet: TBitBtn;
    DBGrid1: TDBGrid;
    DataSource1: TDataSource;
    ADOQuery1: TADOQuery;
    procedure btnShowFormClick(Sender: TObject);
    procedure ConnetClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;
  function ConnDatabase(ServerName,DBName,LoginID,LoginPass:String;AHandle:THandle):Boolean;stdcall; external'ConnectDatabase.dll';
  procedure ShowForm(AHandle: THandle);stdcall;external'ConnectDatabase.dll';
implementation{$R *.dfm}procedure TForm1.btnShowFormClick(Sender: TObject);
var
  AHandle: THandle;
begin
  AHandle := Application.Handle;
  ShowForm(AHandle);
end;procedure TForm1.ConnetClick(Sender: TObject);
var
  AHandle: THandle;
begin
  AHandle := Application.Handle;
  if ConnDatabase('SB11','SB11','SB11ID','SB11IDPassWord',AHandle) then
     MessageDlg('OK.', mtInformation,[mbOk], 0);
end;end.
执行ConnDatabase('SB11','SB11','SB11ID','SB11IDPassWord',AHandle)时出错,提示如下:
Access violation at address 002DB137 in module 'ConnectDatabase.dll'.Read of address 00000324.动态库DLL如下:
unit U_DataBaseSetForm;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, SUIForm, StdCtrls, SUIURLLabel, SUIButton, DB, ADODB,ActiveX;type
  TDataBaseSetForm = class(TForm)
    suiForm1: TsuiForm;
    Panel1: TPanel;
    btnSave: TsuiButton;
    btnCancle: TsuiButton;
    Panel2: TPanel;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    edtServerName: TEdit;
    edtDBName: TEdit;
    edtLoginID: TEdit;
    edtPassWord: TEdit;
    ADOCon: TADOConnection;
    procedure btnSaveClick(Sender: TObject);
    procedure btnCancleClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  DataBaseSetForm: TDataBaseSetForm;
  ConnString:String;
  procedure ShowForm(Ahandle: THandle);stdcall;
  function ConnDatabase(ServerName,DBName,LoginID,LoginPass:String; AHandle: THandle):Boolean;stdcall;
implementation{$R *.dfm}procedure ShowForm(AHandle: THandle);
var    DataBaseSetForm:TDataBaseSetForm;
begin
    Application.Handle := AHandle;
    DataBaseSetForm:=TDataBaseSetForm.Create(Application);
    DataBaseSetForm.ShowModal;
    DataBaseSetForm.Free;
end;function ConnDatabase(ServerName,DBName,LoginID,LoginPass:String ; AHandle: THandle):Boolean;stdcall;
begin
  Application.Handle := AHandle;
  ConnString := 'Provider=SQLOLEDB.1;Password=' + LoginPass +';Persist Security Info=True;User ID=';
  ConnString := ConnString + LoginID +';Initial Catalog=' + DBName + ';Data Source='+ServerName;
  with DataBaseSetForm do
  begin
     DataBaseSetForm.ADOCon.ConnectionString := ConnString;
    try
      ADOCon.Connected;
      Result:=True;
    except
      Result:=False;
    end;
  end;
end;procedure TDataBaseSetForm.btnSaveClick(Sender: TObject);
begin
//如果在此事件中参数调用ConnDatabase也会出错,提示同上!
  ConnString := 'Provider=SQLOLEDB.1;Password=' + Trim(edtPassWord.Text) +';Persist Security Info=True;User ID=';
  ConnString := ConnString + Trim(edtLoginID.Text) +';Initial Catalog=' + Trim(edtDBName.Text) + ';Data Source='+Trim(edtServerName.Text);  ADOCon.ConnectionString:= ConnString;
  try
    ADOCon.Connected;
    Application.MessageBox('连接成功!', '系统提示', MB_OK);
  except
    ADOCon.Free;
    Application.MessageBox('数据库连接失败!', '系统提示', MB_OK);
  end;
end;procedure TDataBaseSetForm.btnCancleClick(Sender: TObject);
begin
  Close;
end;initialization
  CoInitialize(nil); 
finalization
  CoUnInitialize;end.

解决方案 »

  1.   

    学习
    帮你顶
    没有用过dll里面用窗体
      

  2.   

    你是先执行btnShowFormClick再执行ConnDatabase的麽?
      

  3.   

    在dll的项目文件中里引用ShareMem,注意一定是第一个引用;或者把函数中string类型的参数换成pchar的
      

  4.   

    to:我是分开执行的!执行btnShowFormClick后再执行btnSaveClick没有出错!
    执行ConnetClick调用ConnDatabase时出错!
    procedure TForm1.btnShowFormClick(Sender: TObject);
    var
      AHandle: THandle;
    begin
      AHandle := Application.Handle;
      ShowForm(AHandle);
    end;procedure TForm1.ConnetClick(Sender: TObject);
    var
      AHandle: THandle;
    begin
      AHandle := Application.Handle;
      if ConnDatabase('SB11','SB11','SB11ID','SB11IDPassWord',AHandle) then
         MessageDlg('OK.', mtInformation,[mbOk], 0);
    end;
     
    to:wanwangzhiwang(万王之王) ( ) 
    我在dll的项目文件中已经引用ShareMem!但还是不行!
      

  5.   

    感觉你的ADOCon: TADOConnection;只在ShowForm函数中有效,因为它是TDataBaseSetForm的成员变量,你直接执行ConnDatabase时,DataBaseSetForm.ADOCon是个无效指针。编译没有错是因为你在unit U_DataBaseSetForm中定义了个全局变量叫DataBaseSetForm:TDataBaseSetForm;而且,你也没有创建它啊。
      

  6.   

    to:eastliangliang(青苹果)(汉有游女,之子于归) 
    你说得不错!我将ConnDatabase作了如下修改就可以了!
    function ConnDatabase(ServerName,DBName,LoginID,LoginPass:String ; AHandle: THandle):Boolean;stdcall;
    var
      DataBaseSetForm :TDataBaseSetForm ;
    begin
      Application.Handle := AHandle;
      ConnString := 'Provider=SQLOLEDB.1;Password=' + LoginPass +';Persist Security Info=True;User ID=';
      ConnString := ConnString + LoginID +';Initial Catalog=' + DBName + ';Data Source='+ServerName;
      DataBaseSetForm :=TDataBaseSetForm .Create(Application);
      with DataBaseSetForm do
      begin
         m_Connect:=False;
        ADOCon.ConnectionString := ConnString;
        try
          ADOCon.Connected:=True;
          m_Connect:=True;
        except
          m_Connect:=False;
        end;
        Result:=m_Connect;
      end;
      DataBaseSetForm .Free;
    end;但我增加了如下的函数:
    function FindAllRecord:_RecordSet;stdcall;
    begin
      DataBaseSetForm :=DataBaseSetForm .Create(Application);
      DataBaseSetForm .ADOQ1.ConnectionString:=ConnString;
      DataBaseSetForm .ADOQ1.Close;
      DataBaseSetForm .ADOQ1.SQL.Clear;
      DataBaseSetForm .ADOQ1.SQL.Add('Select * from u_user');
      DataBaseSetForm .ADOQ1.Open;
      m_Record:=DataBaseSetForm .ADOQ1.Recordset;
      result:=m_Record As _Recordset;
      DataBaseSetForm .Free;
    end;在另一工程中进行如下调用:
    procedure TForm1.btnFindAllClick(Sender: TObject);
    var
      AHandle: THandle;
    begin
      AHandle := Application.Handle;
      if ConnDatabase('SB11','SB11','SB11ID','SB11IDPassWord',AHandle) then
         ADOQ_1.Recordset:=FindAllRecord(AHandle)
      else
         MessageDlg('数据库连接失败!', mtInformation,[mbOk], 0);
    end;
    调用成功,但关闭此应用程序时出错!提示如下:
    "0x002336d6"指令引用的"0x00d32468"内存.该内存不能为"read".
    按下"确定"后出现下边的错误提示:
    Runtime error 216 at 002336D6
      

  7.   

    没有看出来错在哪里,估计是某些资源未正确释放,请其他高人帮忙看看。个人建议:楼主这次解决问题后,多看些面向对象类的书,将unit U_DataBaseSetForm;内的代码梳理一下,个人感觉写的有点乱。
      

  8.   

    Dll里赋进来的Application.Handle在释放时,必须赋会原来的Handle,也就是在Dll的初始用个变量保存Dll原来的Application.Handle,在释放是赋回原来的Handle.
      

  9.   

    用动态调用就没有问题type
    TShowForm =  procedure(AHandle: THandle);
    var
    LibHandle: integer;
      ShowForm:TShowForm;
    begin
      LibHandle := loadLibrary(PChar('ConnectDatabase.dll'));
      try
      if LibHandle <> 0 then
      begin
        @ShowForm := GetProcAddress(LibHandle,'ShowForm');    if @ShowForm <> nil then
        begin
          //调用动态链接库中主窗体的ShowModal方法
          ShowForm(application.handle);
        end;
      end
    else begin
    MessageDlg('没有发现插件:',mtwarning,[mbok],0);
    exit;
      end;
      finally
        FreeLibrary(LibHandle);
      end;