星期四, 九月 13, 2007

innosetup对bde打包安装

一个朋友拿来一套软件,让我帮着做一个安装程序,这套软件是用Delphi开发的,其中用到了BDE,因此要求把BDE也一起打包安装。

我没用过BDE,更加不熟悉BDE的组成,刚开始不知道如何下手。由于我习惯使用InnoSetup来制作安装程序,便想到在InnoSetup的网站上也许有相关的介绍。于是登录InnoSetup的网站,在FAQ中找到了解决办法,现总结一下:

一、首先,在InnoSetup的网站上下载BdeInst.cab、MiniReg.exe、AddAlias.exe三个程序,其中BdeInst.cab就是BDE的安装包,其中只包含BdeInst.dll一个文件,有3兆多,将它提取出来。

二、将BdeInst.dll、MiniReg.exe、AddAlias.exe与要安装的应用程序放在一起。

三、在制作好的InnoSetup脚本中的相关节中加入以下内容:

[Files]
Source: "BdeInst.dll"; DestDir: "{tmp}"
Source: "MiniReg.exe"; DestDir: "{tmp}"
Source: "AddAlias.exe"; DestDir: "{tmp}"

[Run]
Filename: "{tmp}\MiniReg.exe"; Parameters: """{tmp}\BdeInst.dll"""
Filename: "{tmp}\AddAlias.exe"; Parameters: """Alias SubDir Driver"""

经过这样的改动,制作出来的Setup.exe就可以将应用程序连同BDE一块安装了。

之所以要用到MiniReg.exe和AddAlias.exe,是因为BdeInst.dll其实是一个COM组件,拷贝到用户机器上以后还需要注册一下才能用,MiniReg.exe就是做这个工作的,它的功能类似RegSvr32(不明白为什么不直接使用RegSvr32), MiniReg.exe是用Delphi编写的,源程序很短,顺便列在下面:

// FileName: MiniReg.dpr
program MiniReg;
{
  MiniReg v1.0 by Jordan Russell

  Note: For Delphi 3+, you'll need to change "OLE2" below to "ActiveX".
}
uses
  Windows, OLE2; // ActiveX

{x$R *.RES}

procedure RegisterServer(const Filename: String);
var
  LibHandle: THandle;
  RegisterServerProc: function: HRESULT; stdcall;
begin
  LibHandle := LoadLibrary(PChar(Filename));
  if LibHandle <> 0 then
  try
    @RegisterServerProc := GetProcAddress(LibHandle, 'DllRegisterServer');
    if Assigned(@RegisterServerProc) then
      RegisterServerProc;
  finally
    FreeLibrary(LibHandle);
  end;
end;

begin
  if ParamCount <> 1 then
    Exit;
  CoInitialize(nil);
  try
    RegisterServer(ParamStr(1));
  finally
    CoUninitialize;
  end;
end.

AddAlias的作用是向BDE注册一个别名,指向要连接的数据库(类似ODBC的数据源),它运行时需要三个命令行参数,分别是:别名、子目录名、驱动名。AddAlias也是用Delphi写的,源代码如下:

// FileName: AddAlias.dpr
program AddAlias;
{
  program adds a alias to the BDE configuration file

  parameters:
    0: programname + path (standard parameter of OS)
    1: Name of alias
       if begins with '-' then delete first if exist
                         else do nothing if exist
    2: path to data directory
    3: BDE driver name

  Bugfix: Savierhs Lopez Arteaga 3.1.2001
          AddAlias didn't delete alias with beginning '-'
}

uses
  Windows, SysUtils, BDE;

var
  GAlias:    string  = 'New';
  GDriver:   string = szPARADOX;
  GAliasDir: string;
  FParams:   string;
  FDrvName:  string;
  FDelete:   boolean;
  i:         integer;

function StrToOem(const AnsiStr: string): string;
begin
  SetLength(Result, Length(AnsiStr));
  if Length(Result) > 0 then
    CharToOem(PChar(AnsiStr), PChar(Result));
end;

begin
  for i := 1 to ParamCount do
  begin
    case i of
      1: GAlias    := ParamStr(1);
      2: GAliasDir := ParamStr(2);
      3: GDriver   := ParamStr(3);
    end;
  end;

  //default alias
  if GAliasDir = '' then GAliasDir := ExtractFilePath(ParamStr(0))+'Data';

  //should delete alias first? separate alias name
  if GAlias[1] = '-' then
  begin
    FDelete := True;
    //GAlias := Copy(GAlias, 1, Length(GAlias)); Bug
    Delete(GAlias, 1, 1);  //Fix by Savierhs Lopez Artega
  end else FDelete := False;

  FDrvName := GDriver;
  //set Parameters, the driver and server name
  if (CompareText(GDriver, szCFGDBSTANDARD) = 0) or
     (CompareText(GDriver, szPARADOX) = 0)       or
     (CompareText(GDriver, szDBASE) = 0)         or
     (CompareText(GDriver, szFOXPRO) = 0)        or
     (CompareText(GDriver, szASCII) = 0)         then
  begin
    if (CompareText(GDriver, szCFGDBSTANDARD) = 0) then FDrvName := szPARADOX;

    //set parameters for the new alias
    FParams := Format('%s:"%s"',  [szCFGDBPATH, GAliasDir]) +
               Format(';%s:"%s"', [szCFGDBDEFAULTDRIVER, GDriver]) +
               Format(';%s:"%s"', [szCFGDBENABLEBCD, szCFGFALSE]);
  end else begin
    if (CompareText(GDriver, 'INTRBASE') = 0)
    then FParams := Format('%s:"%s"',  [szSERVERNAME, GAliasDir])
    else FParams := Format('%s:"%s"',  [szDATABASENAME, GAliasDir]);

    //add other Parameters here !!!!!!!!!!!!!!!!!
  end;

  DbiInit(nil);
  try
    if FDelete then
      try
        DbiDeleteAlias(nil, PChar(GAlias));
      except
      end;

    try
      DbiAddAlias(nil, PChar(StrToOem(GAlias)),
                       PChar(StrToOem(FDrvName)),
                       PChar(FParams), True);
      DbiCfgSave(nil, nil, True);
    except
    end;

  finally
    DbiExit();
  end;

end.

杂感:

一、InnoSetup这个安装制作工具非常好用,它短小精致、公开源码、无需注册可免费使用,能满足绝大多数需要,我经常向人建议抛弃InstallShield这个庞然大物,使用InnoSetup。

二、原来的印象中,BDE也是个庞然大物,有10兆之巨,但这次的安装包只有3兆,很出乎意料。