[返回]
中国计算机报2000年第55期

在Delphi程序中动态创建ODBC数据源

林 琪

  在开发Delphi应用程序中,经常会遇到在程序中动态设置数据源的问题。如果使用到一些分布式数据库或Access数据库,还可能需要建立相应的ODBC关联,因此数据源设置问题不仅体现为BDE数据源的设置,还需要完成ODBC数据源的设置。

  以Access数据库为例,我们在实际编程中发现,如果不建立ODBC数据源,即只建立MSAccess类型的BDE数据源,虽然可以避开ODBC数据源设置的麻烦,但在Delphi中利用此数据源生成报表时会出现死机现象。如果确实需要使用Access数据库,而且应用程序需要报表功能时,利用程序完成ODBC数据源的设置就必不可少了。


  一、实现方法


  我们在用VC编程中曾经通过调用函数SQLCreateDataSource动态创建过ODBC数据源,其作用是设置好数据源名后,自动提示用户选择所需连接的数据库名,使用相当灵活。由于在Delphi的接口函数库中找不到它,笔者就自己动手做一个函数库,旨在提供一个标准接口。下面将介绍具体实现方法:

  1.动态链接库的设计

  在VC++ 6.0环境下设计了一个动态链接库DLL(ODBCDLL),核心就是设计输出函数creatodbc,其作用是创建ODBC数据源。

  首先利用AppWizard创建一个动态链接库工程ODBCDLL.dsw,在主程序ODBCDLL.cpp中实现函数定义。

  函数声明为void creatodbc(HWND hld,char strDSN),其中hld参数为窗口句柄,strDSN为ODBC数据源名。

  void creatodbc(HWND hld,char strDSN)

  {

  SQLCreateDataSource(hld, strDSN);

  }

  接着建立头文件odbcapi.h,用来建立公共函数的输出接口:

  #ifndef _ODBCAPI_H_

  #define _ODBCAPI_H_

  //__declspec(dllexport)

  extern "C" {

   void creatodbc(HWND hld,char  strDSN);

  }

  #endif

  编译生成ODBCDLL.dll后,就可着手下一步设计。

  2.Delphi接口单元的设计

  有了动态链接库,下一步需要使用其中的函数creatodbc,根据ODBCAPI.h的内容设计接口单元ODBCAPI.pas,这一步非常重要,否则不能链接成功。

  接口单元ODBCAPI.pas内容为:

  unit ODBCAPI;

  interface

  uses

  {$IFDEF WIN32}

   Windows;

  {$ELSE}

   Wintypes, WinProcs;

  {$ENDIF}

  {=> ODBCAPI.H <=}

  {$IFNDEF _ODBCAPI_H_}

  {$DEFINE _ODBCAPI_H_}

  {///__declspec(dllexport) }

  procedure creatodbc(hld: HWND;

   strDSN: PChar) {$IFDEF WIN32} cdecl {$ENDIF};

  {$ENDIF}

  implementation

  procedure creatodbc; external 'ODBCDLL.DLL';

  end.

  函数声明中需要注意到,由于VC和Delphi的类型有所差异,需要将strDSN的类型调整为PChar。

  下面,可以开始实现动态创建ODBC数据源了。

  3. ODBC数据源的创建

  要使用creatodbc函数创建ODBC数据源,首先将接口单元加入到工程中,并在相应文件中进行声明:

  uses ODBCAPI;

  在事件响应函数中设置变量hd用来标识主应用的主窗口句柄,它将在调用creatodbc时用到。若创建的ODBC数据源名为my_new_data,设置如下:

  procedure TSETUP.SpeedButton1Click(Sender: TObject);

  var

   hd:HWND;

  begin

   hd:=application.Handle;

   creatodbc(hd,'my_new_data');

  end;


  二、实例应用


  一般来讲,创建数据源的工作总是在首次进入安装时完成,我们可以模拟一个安装过程,包括设置安装进程条、创建ODBC数据源,特别是需要在创建ODBC数据源后相应调整BDE数据源的设置。

  首先来看调整BDE数据源的方法,由于Delphi应用中存在一个非常好用的默认变量Session,所以这个过程就相对简单多了。

  设计一个方法creatAlias,其作用是建立与ODBC数据源相关的BDE数据源别名,参数AliasString表示建立的别名,database则为ODBC数据源名,这里以Access数据库为例,因此将ODBC数据源的驱动设置为“Microsoft Access Driver (.mdb)”,如果必要,可以将驱动程序本身也作为参数在程序中设置,将进一步增加其灵活程度。如果别名已经存在,系统将会自动删除,并以新创建的别名为准。定义如下:

  procedure TSETUP.creatAlias (AliasString,database : String);

  var

  MyList : TStringList;

  const

  Driver = 'Microsoft Access Driver (*.mdb)';

  begin

   MyList:=TStringList.Create;

   try

   With MyList do

   begin

   Add('DATABASE NAME= ');

   Add('ODBC DSN='+database);

   Add('USER NAME= ');

   end;

   if Session.IsAlias(AliasString) then

   begin

  Session.DeleteAlias

   (AliasString);

  Session.SaveConfigFile;

  end;

  Session.AddAlias(AliasString,Driver,MyList);

  Session.SaveConfigFile;

  finally

  myList.Free;

  end;

  end;

  编写安装按钮的响应事件代码如下:

  procedure TSETUP.SpeedButton1Click(Sender: TObject);

  var

   hd:HWND;

   F: TextFile;

   i,count:integer;

   staPanleWidth:integer;

  begin

  progress:=TProgressbar.create(setup);

  count:=3000; //进程条的最大值

  staPanleWidth:=status.Panels.Items[2].width;

  status.Panels.Items[2].width:=150; // 改变宽度

  status.repaint;

  with progress do

  begin

  top:=StatusDrawRect.top;

  left:=StatusDrawRect.left;

  width:=StatusDrawRect.right-StatusDrawRect.left;

  height:=StatusDrawRect.bottom-StatusDrawRect.top;

  //设定进程条的宽度和高度

  visible:=true;

  Parent := status; //该进程条的拥有者为状态条status

  Min := 0; Max := Count; //进程条的最大和最小值

  Step := 1; //进程条的步长

  for i := 1 to round(count/5) do

  Stepit; // 累加进程条

  //这里可以分发证书

  for i := 1 to round(count/5) do

  Stepit; // 累加进程条

  //这里可以检查证书的合法性

  for i := 1 to round(count/5) do

  Stepit; // 累加进程条

  //这里可以检查时间是否合法

  for i := 1 to round(count/5) do

  Stepit; // 累加进程条

  //创建ODBC数据源

  hd:=application.Handle;

  creatodbc(hd,'my_new_data');

  for i := 1 to round(count/5) do

  Stepit; // 累加进程条

  creatAlias('my_new_data','my_new_data');

  //建立BDE别名

  Free; //释放进程条

  end; //with

  status.Panels.Items[2].width:=staPanleWidth;

  //恢复状态条嵌板的宽度

  end;

  以上程序已在Delphi 4.0、Windows 98平台上运行通过。