作者:毕照杰
    前年在一个网站作版主的时候,应网友的要求,我写了一篇文章,《如何把应用程序程序和ORACLE客户端一起打包》,说明如何制作ORACLE客户端,后边本来是要附加上如何用程序来配置ORACLE连接串的(一般的用户是用NET CONFIG或net assistant来手工配置),因为比较懒散,一直没有写,今天补上,同时为了大家阅读方便,我把《如何把应用程序程序和ORACLE客户端一起打包》这篇文章也写在一起,希望能给大家带来帮助。
    一、如何打包ORACLE客户端。
    我们在做程序的时候,经常会需要安装ORACLE的客户端,如果客户终端非常多的时候,这就会是一项很麻烦的工作,一方面要安排我们的应用程序,另一方面要安装RACLE客户端,而且还要对ORACLE客户端进行NET EASY配置,真是不胜其烦。
    经过研究,我做到了可以把ORACLE客户端和应用程序一起打包,又自己用程序来配置NET EASY。
    1、打包要知道的问题:
      A、要打包哪些文件。
      B、如何修改注册表。
      C、如何设置环境变量。
      D、打包使用哪些工具。
    2、打包要使用的文件:
    我们先找一个装有ORACLE的机器,把以下的文件打包。为了保证ORACLE能正常访问,我们需要保持原目录结构不变。
      A、$ORACLE_HOME\BIN下边所有DLL,IMP.EXE,EXP.EXE,SQLPLUS.EXE,SQLPLUSW.EXE。($ORACLE_HOME指的是ORACLE的主目录,比如D:\ORACLE\ORA8I)。
      B、$ORACLE_HOME\network目录下的三个目录:Admin、mesg、tnsapi,把它们全部打包。
      C、$ORACLE_HOME\ocommon\nls目录。
      D、$ORACLE_HOME\oracore\mesg目录。
      E、$ORACLE_HOME\sqlplus下的两个目录:admin、mesg。
    3、如何修改注册表:
    为不麻烦,我们可以把这个装有ORACLE的机器的注册表里边ORACLE信息照搬过来。全部照抄。
    4、如何设置环境变量:
    设置环境变量,我们要在PATH前边加上$ORACLE_HOME\BIN;
    5、使用哪些打包工具:
      我个人比较喜欢的工具是WiseInstaller,它的功能很强大,能导入整个文件目录(我感觉这一点比Install shilled要好)、导入注册表、也可以设置环境变量,以及设置NT服务等等(我好象是给它做广告似的)。
      我们现在就可以使用它来做我们的客户端了。
      第一步,先把我说的这些文件目录全部导入到我们的安装工程中去。
      第二步,找到设置注册表选项,导入注册表中HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE下边所有的注册表值。
      第三步,找到环境变量设置选项,在它的PATH那里加上$ORACLE_HOME\BIN。这里的$ORACLE_HOME用<Installdir>来代替。
      做完这一切,编译,发布,OK。
6、如何用手工来修改NET EASY。
      现在我们已经做完了这个安装包,并且把它安装到了我们的电脑上边,那么,在开始菜单上是没有ORACLE这个选项的,如何设置ORACLE NET EASY呢?
      我们现在暂时可以这样做:
      打开我们的ORACLE客户端的安装目录,找到NETWORK\ADMIN子目录下边的tnsnames.ora这个文件,直接对它进行编辑就行了。
      比如,我们现在想配置一个叫做NTSERVER的服务名,我们就可以这样写:
      NTSERVER =
        (DESCRIPTION =
          (ADDRESS_LIST =
             (ADDRESS = (PROTOCOL = TCP)(HOST = 机器名)(PORT = 端口号))
          )
         (CONNECT_DATA =
         (SERVICE_NAME = 全局数据库名)
        )
        )
      然后,直接把它加到tnsnames.ora这个文件的后边就行了。
      如果NTSERVER这个服务名已经存在的话,我们可以直接修改它的机器名、
      端口号和全局数据库名就可以了。

解决方案 »

  1.   

    作者:毕照杰
        前年在一个网站作版主的时候,应网友的要求,我写了一篇文章,《如何把应用程序程序和ORACLE客户端一起打包》,说明如何制作ORACLE客户端,后边本来是要附加上如何用程序来配置ORACLE连接串的(一般的用户是用NET CONFIG或net assistant来手工配置),因为比较懒散,一直没有写,今天补上,同时为了大家阅读方便,我把《如何把应用程序程序和ORACLE客户端一起打包》这篇文章也写在一起,希望能给大家带来帮助。
          二、如何用程序来配置ORACLE数据库连接          
          1、更改的参数
          我们知道,ORACLE把数据库的连接信息都保存在tnsnames.ora这个文件里边的,所以我们可以手工更改这个文件来连接数据库,由于现在的版本一般都采用TCL/IP来连接数据库,那对我们来说,一般只要更改几个地方就可以了:
            A、数据库连接名,比如前边的NTSERVER。
            B、机器名(或IP)。
            C、端口号,默认是1521,也有其它端口的。 
            D、全局数据库名。  
          2、文件的位置
          一般来说,这个文件是放在当前$ORACLE_HOME/network/admin下边,如果在本机上装有多个数据库,则有多个这样的文件,最好一起更改,可以通过注册表来查找当前有几个ORACLE目录。我们通过HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\ALL_HOMES\HOME_COUNTER可以看出ORACLE的个数。
          当然,也有比较省力一点的作法,就是把$ORACLE_HOME/network/admin下的tnsnames.ora这个文件放到当前的可执行程序的目录下,则在执行程序的时候,应用程序的连接会以当前目录下的tnsnames.ora的配置为准。
          3、具体作法
          A、在当前目录下放一个临时文件,tnsname.sql,内容如下:
             %S =
               (DESCRIPTION =
                 (ADDRESS_LIST =
                   (ADDRESS = (PROTOCOL = TCP)(HOST = %s)(PORT = %d))
                 )
                 (CONNECT_DATA =
                   (SERVICE_NAME = %s)
                 )
               )
          B、程序写法(DELPHI语言)
          
          1)取得ORACLE个数
          function OracleCount: Integer;
          var
            OraNum: Integer;
            reg: TRegistry;
          begin
            OraNum := 0;
            Reg := TRegistry.Create;
            try
              reg.RootKey := HKEY_LOCAL_MACHINE;
              if Reg.OpenKey('SOFTWARE\ORACLE\ALL_HOMES', True) then
              begin
                //这里考虑有多个数据库的情况。
                OraNum := StrToInt(Reg.ReadString('HOME_COUNTER'));
              end;
              Reg.CloseKey;
              Result := OraNum;
            finally
              Reg.Free;
            end;
          end;    
          
          2)取得单个ORACLE目录
          function GetOraHome(HomeIndex: Integer): string;                                 
          var                                                                              
            reg: TRegistry;                                                                
            OraHome: string;                                                               
          begin                                                                            
            Reg := TRegistry.Create;                                                       
            try                                                                            
              reg.RootKey := HKEY_LOCAL_MACHINE;                                           
              if Reg.OpenKey('SOFTWARE\ORACLE\ALL_HOMES\ID' + IntToStr(HomeIndex), True)   
                then                                                                       
              begin                                                                        
                //这里考虑有多个数据库的情况。                                             
                OraHome := Reg.ReadString('PATH');                                         
                if Copy(OraHome, Length(OraHome), 1) = '\' then                            
                  Delete(OraHome, length(OraHome), 1);                                     
              end;                                                                         
              Reg.CloseKey;                                                                
              Result := OraHome;                                                           
            finally                                                                        
              Reg.Free;                                                                    
            end;                                                                           
          end;      
          
          3)设置单个ORACLE连接
          procedure SetLink(OraFile: string; LinkName: string; Host: string; Port:
            Integer; DbName: string);
          var
            FileVar: TextFile;
            Str: string;
            CanCopy: Boolean; //看是否可以COPY
            TnsFile, TmpFile, SqlFile: string;
            Num: Integer;
            LastStr: string;
          begin
            CanCopy := True;
            try
              SqlFile := '' + CurDir + '\tnsnames.sql' + '';
              TnsFile := '' + OraFile + '';
              TmpFile := '' + CurDir + '\tnsnames.tmp' + '';
              Num := 0;
          
              //先把本地的一个TMP文件写一下。使它等于连接字符串
              AssignFile(FileVar, SqlFile);
              Reset(FileVar);
              while not Eof(FileVar) do
              begin
                Num := Num + 1;
                ReadLn(FileVar, Str);
                //注意,这里用大写来区分,以下两个都是小写
                if (pos('%S', Str) > 0) then
                  Str := Format(Str, [LinkName]);
                if (pos('%s', Str) > 0) and (pos('%d', Str) > 0) then
                  Str := Format(Str, [Host, Port]);
                if (pos('%s', Str) > 0) and not (pos('%d', Str) > 0) then
                  Str := Format(Str, [DbName]);
                if Num = 1 then
                  TraceLog(TmpFile, Str, 'r')
                else
                  TraceLog(TmpFile, Str, 'a');
              end;
              CloseFile(FileVar);
          
              //读取旧的TNSNAMES.ORA,把它写入到本地的TMP文件中。
              AssignFile(FileVar, TnsFile);
              if FileExists(TnsFile) then
                Append(FileVar)
              else
                ReWrite(FileVar);
              Reset(FileVar);
              while not Eof(FileVar) do
              begin
                ReadLn(FileVar, Str);
                lastStr := Str;
                if not (pos(LinkName + ' =', UpperCase(Str)) > 0) and CanCopy
                  and not (pos('#', Str) > 0) then
                  TraceLog(TmpFile, Str, 'a');
                if pos(LinkName + ' =', UpperCase(Str)) > 0 then
                  CanCopy := False;
                if (CanCopy = False) and (Trim(Str) = '') then
                  CanCopy := True;
              end;
              CloseFile(FileVar);
              //如果是空格,则不用写入,否则,写一行空格在最后
              if Trim(LastStr) <> '' then
                TraceLog(TmpFile, '', 'a');
          
              AssignFile(FileVar, TmpFile);
              Reset(FileVar);
              TraceLog(TnsFile, '# Edited by Bi ZhaoJie  ' +
                FormatDateTime('yyyy-mm-dd hh:mm:ss', now), 'R');
              TraceLog(TnsFile, '', 'a');
              while not Eof(FileVar) do
              begin
                ReadLn(FileVar, Str);
                TraceLog(TnsFile, Str, 'a');
              end;
              CloseFile(FileVar);
              //结束写tnsnames.ora
            except
            end;
          end;        
          
          4)写文本文件
          procedure TraceLog(FileName: string; str: string; WriteType: string);
          var
            FileVar: TextFile;
            sss: string;
          begin
            sss := '' + FileName + '';
            AssignFile(FileVar, sss);
            try
              if UpperCase(WriteType) = 'R' then
                ReWrite(FileVar)
              else
              begin
                if FileExists(sss) then
                  Append(FileVar)
                else
                  ReWrite(FileVar);
              end;
              Writeln(FileVar, Str);
              CloseFile(FileVar);
            except
              ShowMsg('File can not open,check if it is readonly!');
            end;
          end;      
          5)程序最终实现
          for i := 0 to OracleCount - 1 do
          begin
            FileName := GetOraHome(i) + '\network\admin\tnsnames.ora';
            SetLink(FileName, 连接串名, 数据库服务器, 端口,
              全局数据库名);
          end;