杉宫竹苑工作室

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2792|回复: 0

InstallShield 集成安装 MSDE2000

[复制链接]
发表于 2017-3-1 17:05:15 | 显示全部楼层 |阅读模式

正式会员享受无限制浏览网站功能和高速网盘下载,赶快加入本站吧!

您需要 登录 才可以下载或查看,没有账号?立即注册

x
    在网上看到许多关于MSDE2000集成到应用程序中一并安装的文章,这些方法无一例外都使用了InstallShield中调用外部命令的方式,其本质就是在安装过程中调用LaunchAppAndWait函数执行MSDE2000的setup.exe程序,这样一来,带来几个问题:
    1、无法与应用程序的安装一并卸载;
    2、无法实现MSDE2000的最小安装;
    3、如果用户中途取消安装,程序不能完全回滚;
    4、无法与应用程序安装到同一个目录。
    如果使用installshield中的预安装功能,也仅能在MSI工程中使用,同时,也不能灵活地控制安装过程及实现上述功能,为此,我们需要一种方法,用于在安装过程中集成MSDE2000。这是因为许多应用需要SQL Server支持,而MSDE2000确实是一个不错的选择,撇开版权不说,仅全面兼容SQL和支持2G的数据量就足够了,如果能解决安装时的集成问题,就会为极大地方便应用程序的分发。
    下面我通过具体实例来介绍这一方法。
    目标一:实现不可控的最小安装。
    一、数据准备:
    1、下载SQL Server 2000 Desktop Engine (MSDE) 组件(SQL2000.MSDE-KB884525-SP4-x86.EXE)
    2、双击下载的exe文件,解压缩至C:/SQL2KSP4,在运行中浏览至c:/SQL2KSP4/MSDE,找到setup.exe文件,双击它,不要急着点“确定”,在setup.exe后面空一格,接着输入安装参数:INSTANCENAME="fishout" SECURITYMODE=SQL SAPWD="fishout@TOM.COM" /L*v C:/MSDELog.log,点击确定(其中:INSTANCENAME="实例名",SAPWD="密码",可自行修改,以下均以命名实例“fishout”为例),待其安装完毕后不要启动服务,也不要重启机器,将C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/文件夹下的binn、Data、log三个文件夹保留,其余的删除。
    3、准备注册表入口。打开注册表编辑器,导航至:HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server,删除多余的子健,使其看上去如图所示: mdse2000-1-1.jpg
  再在SuperSocketNetLib子键下面的ProtocolList属性中增加两个字符串:tcp/np,右击Microsoft SQL Server,选择导出注册表,文件名任意取,打开并编辑已导出的注册表文件,将安装路径“C:/Program Files/Microsoft SQL Server”替换为“”,使其修改完成的注册表文件如下:

  1. Windows Registry Editor Version 5.00  
  2.   
  3. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server]  
  4. "InstalledInstances"=hex(7):46,00,49,00,53,00,48,00,4f,00,55,00,54,00,00,00,00,/  
  5.   00  
  6. "SsrpActiveServer"=""  
  7. "SqlMdacRegRefCount"=dword:00000001  
  8.   
  9. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server/FISHOUT]  
  10.   
  11. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server/FISHOUT/MSSQLServer]  
  12. "AuditLevel"=dword:00000000  
  13. "DefaultLogin"="guest"  
  14. "ListenOn"=hex(7):53,00,53,00,4d,00,53,00,53,00,48,00,37,00,30,00,00,00,53,00,/  
  15.   53,00,4e,00,45,00,54,00,4c,00,49,00,42,00,00,00,00,00  
  16. "LoginMode"=dword:00000000  
  17. "Map_"="//"  
  18. "Map#"="-"  
  19. "Map[        DISCUZ_CODE_173        ]quot;=""  
  20. "SetHostName"=dword:00000000  
  21. "Tapeloadwaittime"=dword:ffffffff  
  22. "uptime_pid"=dword:000000c8  
  23. "uptime_time_utc"=hex:0e,55,77,e8,59,58,ca,01  
  24.   
  25. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server/FISHOUT/MSSQLServer/CurrentVersion]  
  26. "CurrentVersion"="8.00.194"  
  27. "RegisteredOwner"=""  
  28. "SerialNumber"=""  
  29. "CSDVersionNumber"=dword:00000400  
  30. "CSDVersion"="8.00.1100"  
  31. "Language"=dword:00000804  
  32. "checksum"=hex:38,30,32,32,63,31,35,38,61,65,37,64,34,63,64,37,35,30,64,61,30,/  
  33.   33,34,62,36,30,31,34,32,63,62,61,66,37,30,33,30,38,35,35,65,62,64,63,34,34,/  
  34.   36,62,61,37,35,64,61,62,37,30,34,66,37,33,65,35,30,37,64,65,37,34,30,39,31,/  
  35.   32,65,62,39,35,65,62,36,62,63,37,64,64,37,32,66,62,36,65,39,32,63,61,66,63,/  
  36.   33,30,66,62,30,30,35,64,31,37,30,61,65,61,32,34,61,30,30,63,65,33,64,62,66,/  
  37.   62,61,39,64,61,64,65,30,36,36,30,66,31,62,63,63,35,32,37,33,63,32,62,33,30,/  
  38.   36,31,66,66,61,64,65,36,65,32,30,36,38,34,33,64,00  
  39.   
  40. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server/FISHOUT/MSSQLServer/Parameters]  
  41. "SQLArg0"="-d//MSSQL$FISHOUT//Data//master.mdf"  
  42. "SQLArg1"="-e//MSSQL$FISHOUT//LOG//ERRORLOG"  
  43. "SQLArg2"="-l//MSSQL$FISHOUT//Data//mastlog.ldf"  
  44.   
  45. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server/FISHOUT/MSSQLServer/SuperSocketNetLib]  
  46. "ProtocolList"=hex(7):74,00,63,00,70,00,00,00,6e,00,70,00,00,00,00,00  
  47.   
  48. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server/FISHOUT/MSSQLServer/SuperSocketNetLib/Np]  
  49. "PipeName"="////.//pipe//MSSQL$FISHOUT//sql//query"  
  50.   
  51. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server/FISHOUT/MSSQLServer/SuperSocketNetLib/Tcp]  
  52. "TcpHideFlag"=dword:00000000  
  53. "TcpDynamicPorts"="0"  
  54. "TcpPort"="0"  
  55.   
  56. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server/FISHOUT/Setup]  
  57. "FeatureName"="SqlRun"  
  58. "FirstStart"=dword:00000000  
  59. "ProductCode"="{E09B48B5-E141-427A-AB0C-D3605127224A}"  
  60. "SQLDataRoot"="//MSSQL$FISHOUT"  
  61. "SQLPath"="//MSSQL$FISHOUT"  
  62. "Edition"="Desktop Engine"  
  63. "PatchLevel"="8.4.2039"  
复制代码
    二、设计制作安装程序:
    1、在installshield中新建一个InstallScript Project工程,命名为MDSE2000,在工程文件夹下新建files文件夹,复制刚才安装目录下MSSQL$FISHOUT文件夹到工程files中,复制C:/WINDOWS/System32/msvcp71.dll及msvcr71.dll文件到files/MSSQL$FISHOUT/Binn中(不要遗忘这个文件),设置Product Properties中TARGETDIR内容为:/Microsoft SQL Server,添加files中MSSQL$FISHOUT文件夹到Application Target Folder中。
    2、导入注册表。在Registry注册表入口中右击Destination Computer,单击New Registry Set,重命名为:MDSE2000,右击它,点击:Import REG File...,导入刚才已修改好的注册表设置,在右边勾选与此关联的安装文件组。
    3、在安装脚本中点选DefaultFeature,生成Installed事件,代码如下:
  1. export prototype DefaultFeature_Installed();  
  2. function DefaultFeature_Installed()  
  3.     number nvServiceState;  
  4.     string szServiceName, szServiceDisplayName, szServiceDescription, szServicePathFile, szStartServiceArgs;  
  5.     BOOL bStartService;  
  6. begin  
  7.     // 安装服务  
  8.     szServiceName = "MSSQL$FISHOUT";  
  9.     szServiceDisplayName = "MSSQL$FISHOUT";  
  10.     szServiceDescription = "";  
  11.     szServicePathFile = TARGETDIR ^ "mssql$fishout//Binn//sqlservr.exe -sFISHOUT";  
  12.     bStartService = TRUE;  
  13.     szStartServiceArgs = "";  
  14.     if (ServiceGetServiceState (szServiceName, nvServiceState ) >= ISERR_SUCCESS) then  
  15.         // 停止并卸载原来的服务  
  16.         ServiceStopService ( szServiceName );  
  17.         ServiceRemoveService ( szServiceName );  
  18.     endif;  
  19.     ServiceAddService ( szServiceName, szServiceDisplayName, szServiceDescription, szServicePathFile, bStartService, szStartServiceArgs );  
  20. end;  
复制代码
   4、编译生成安装程序,可以看到,生成的安装包仅有12.4兆,比微软原来的安装包要小多了,非常利于网络传输和应用程序的分发,不过,有一个致命的缺点,就是不支持安装路径的更改,这个问题,放在下一节解决。


  原创文章,转载请注明出处。
  在这一节里,我们解决安装路径的更改问题。大家知道,MSDE2000安装后,数据库路径不能更改,这也是制约许多安装包无法与应用程序一并集成的首要原因,现在我们来解决这一个问题。
  主要思路是通过分离msdb和model数据库,然后更改master数据库的系统目录指向,改为相对目录,最后,通过附加msdb及model并重建tempdb数据库来实现。
  目标:实现集成包的任意目录安装。
  注意:以下操作在前一节基础上继续。
  一、准备数据库
  1、启动先前安装的MSDE2000服务;
  2、使用命令行工具分离并修改系统数据库;
  3、将下面SQL脚本内容保存至:C:/Program Files/Microsoft SQL Server/80/Tools/Binn,文件名命名为:detach.sql。
  1. use master  
  2. [color=#df3434][b][url=http://lib.csdn.net/base/go]Go[/url][/b][/color]  
  3. sp_configure 'allow updates',1  
  4. go  
  5. reconfigure with override  
  6. go  
  7. update sysaltfiles set [filename]='./../data/master.mdf' where [name]='master'  
  8. update sysaltfiles set [filename]='./../data/mastlog.ldf' where [name]='mastlog'  
  9. update sysdatabases set [filename]='./../data/master.mdf' where [name]='master'  
  10. go  
  11. sp_detach_db 'msdb'  
  12. go  
  13. sp_detach_db 'model'  
  14. go  
  15. sp_configure 'allow updates',0  
  16. go  
  17. reconfigure with override  
  18. go  
复制代码
 4、在运行菜单中输入:cmd /k cd C:/Program Files/Microsoft SQL Server/80/Tools/Binn,单击确定,打开命令窗口,在窗口中输入:sc start mssql$fishout -T3608,启动SQL服务,服务成功启动后再输入:osql -S (local)/fishout -E -i detach.sql,执行相对目录更改及分离操作,操作成功后会出现如下画面:
mdse2000-2_1.jpg
  5、接着继续运行以下命令:net stop mssql$fishout,停止SQL服务,至此,数据文件已准备完成,复制C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/下的所有文件至工程文件夹下files/Data中,确认替换。
  二、在安装工程中使用进程方式附加数据库并安装服务
  主要设计思路:
  当文件复制到目标机器结束后,以单用户、跟踪模式启动服务,以便允许对系统目录进行更新,从而,可以在新的安装目录下附加系统数据库,当以进程方式启动服务成功后,通过调用InstallShield中SQL运行时间库函数,将SQL脚本中的路径替换为实际安装路径并执行附加系统数据库的脚本,成功附加后,中止SQL进程,最后安装并启动服务。
  1、建立SQL连接,为安装脚本中使用命令方式执行脚本提供准备。
  2、导入数据库附加脚本
  将以下脚本内容保存至:工程文件夹下的“Script Files”子文件夹中,文件名为:MSDE2000.sql,右击“NewSQLConnection1”,选择“Insert Script Files...”,浏览至工程文件夹下的“Script Files”子文件夹,将“MSDE2000.sql”脚本导入,在导入后的脚本“Text Replacement”处,单击“Add...”按钮添加一条替换记录,以便实现安装路径的变换,如图:
mdse2000-2_2.jpg
  1. if not exists (select name from master.dbo.sysdatabases where name = 'model')  
  2. begin  
  3.     exec master..sp_attach_db 'model','C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/model.mdf','C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/modellog.ldf'  
  4.     exec master..sp_attach_db 'msdb','C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/msdbdata.mdf','C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/msdblog.ldf'  
  5.     exec master..sp_resetstatus tempdb  
  6.     Alter database tempdb modify file (name = tempdev, filename = 'C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/tempdb.mdf')  
  7.     Alter database tempdb modify file (name = templog, filename = 'C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/templog.ldf')  
  8. end  
复制代码
  3、导入进程中止脚本。
  引用前人已写的现成脚本,将以下脚本内容保存至:工程文件夹下的“Script Files”子文件夹中,文件名为:ShutDownRunningApp.rul,单击面板中“InstallScript”,右击“Files”,选择“Insert Script Files...”,浏览至工程文件夹下的“Script Files”子文件夹,将“ShutDownRunningApp.rul”脚本导入,需要使用这个脚本来实现SQL进程的中止。
  1. //////////////////////////////////////////////////////////////////////////////  
  2. //  
  3. // Description: Windows NT process control functions.  
  4. //  
  5. //              The process code is adapted from code posted by William F.  
  6. //              Snodgrass to [url]www.installsite.org.[/url] The original code header  
  7. //              is appended below. The array code is adapted from code posted  
  8. //              by Rajesh Ramachandran to the installshield.is6.installscript  
  9. //              newsgroup.  
  10. //   
  11. // Submitted by Richard Iwasa ([email]riwasa@email.com[/email]).  
  12. //  
  13. // Usage example:  
  14. //  
  15. // if ProcessRunning("notepad") then  
  16. //      MessageBox("Application is running.", INFORMATION);  
  17. //  
  18. //      ProcessEnd("notepad");  
  19. //         
  20. //      Delay(2);  // Delay to allow process list to refresh  
  21. //         
  22. //      if ProcessRunning("notepad") then  
  23. //          MessageBox("Application is running.", INFORMATION);  
  24. //      else  
  25. //          MessageBox("Application is not running.", INFORMATION);  
  26. //      endif;  
  27. //  else  
  28. //      MessageBox("Application is not running.", INFORMATION);  
  29. //  endif;  
  30. //  
  31. // Original code header appended below:  
  32. //  
  33. // GetRunningApp();  
  34. // ShutDownApp();  
  35. //   
  36. // These script created functions will look for any running application  
  37. // based on the file name, then display an error message within the Setup.  
  38. // You can optionally halt the install or just continue on.  
  39. //   
  40. // You can use the ShutDownApp() function for shutting down that process  
  41. // or others as well. This is useful for processes that run in the   
  42. // background but have no Windows associated with them. May not work with  
  43. // Services.  
  44. //   
  45. // This script calls functions in PSAPI.DLL that are not supported on   
  46. // Windows 95 or 98.  
  47. //   
  48. // ***Instructions***  
  49. // Place these script peices into the Setup.rul file.  
  50. //   
  51. // Modify the script to include the applications you would like to get or  
  52. // shutdown.  
  53. //   
  54. // Submitted by William F. Snodgrass  
  55. // Contact info: [email]bsnodgrass@geographix.com[/email]  
  56. //   
  57. // Created by Theron Welch, 3/3/99  
  58. // Minor modifications by Stefan Krueger, 11/03/99  
  59. //   
  60. // Copyright (c) 1999-2000 GeoGraphix, Inc.   
  61. //  
  62. //////////////////////////////////////////////////////////////////////////////  
  63.   
  64.   
  65.   
  66. /////////////////////////////////////////////////  
  67. // Function prototypes.  
  68. /////////////////////////////////////////////////  
  69.   
  70. prototype POINTER ArrayToPointer(BYREF VARIANT);  
  71. prototype NUMBER  ProcessEnd(STRING);  
  72. prototype BOOL    ProcessRunning(STRING);  
  73.   
  74. // Kernel functions.  
  75.   
  76. prototype NUMBER Kernel32.OpenProcess(NUMBER, BOOL, NUMBER);  
  77. prototype NUMBER Kernel32.TerminateProcess(NUMBER, NUMBER);  
  78.   
  79. // Process information functions.  
  80.   
  81. prototype NUMBER PSAPI.EnumProcesses(POINTER, NUMBER, BYREF NUMBER);  
  82. prototype NUMBER PSAPI.EnumProcessModules(NUMBER, BYREF NUMBER, NUMBER,  
  83.         BYREF NUMBER);  
  84. prototype NUMBER PSAPI.GetModuleFileNameExA(NUMBER, NUMBER, BYREF STRING,  
  85.         NUMBER);  
  86.   
  87.   
  88.   
  89. /////////////////////////////////////////////////  
  90. // Structures.  
  91. /////////////////////////////////////////////////  
  92.   
  93. // Structure to mirror the C/C++ SAFEARRAY data structure.  
  94.   
  95. typedef _SAFEARRAY  
  96. begin  
  97.     SHORT   cDims;  
  98.     SHORT   fFeatures;  
  99.     LONG    cbElements;  
  100.     LONG    cLocks;  
  101.     POINTER pvData;  
  102.     // rgsaBound omitted  
  103. end;  
  104.   
  105. // Structure to mirror the C/C++ VARIANT data structure.  
  106.   
  107. typedef _VARIANT  
  108. begin  
  109.     SHORT  vt;  
  110.     SHORT  wReserver1;  
  111.     SHORT  wReserved2;  
  112.     SHORT  wReserved3;  
  113.     NUMBER nData;  
  114. end;  
  115.   
  116.   
  117.          
  118. /////////////////////////////////////////////////  
  119. // Constants.  
  120. /////////////////////////////////////////////////  

  121. #define PSAPI_FILE        "psapi.dll"  // Windows NT process DLL  
  122. #define PROCESSID_LENGTH  4            // 4 bytes (DWORD) for a process ID  
  123.   
  124. // Process information constants.  

  125. #define PROCESS_QUERY_INFORMATION  0x400  
  126. #define PROCESS_ALL_ACCESS         0x1f0fff  
  127. #define PROCESS_VM_READ            0x10  
  128.   
  129.   
  130.   
  131. //////////////////////////////////////////////////////////////////////////////  
  132. //  
  133. // Function:    ArrayToPointer  
  134. //  
  135. // Description: Converts an InstallShield array into a C array.  
  136. //  
  137. //              When an array is created in InstallScript, a VARIANT variable  
  138. //              is created which holds an OLEAutomation SAFEARRAY. To pass  
  139. //              such an array to a DLL function expecting a C-style array,  
  140. //              this function explicitly typecasts the pointer to the array  
  141. //              to a _VARIANT pointer so that the _SAFEARRAY pointer can be  
  142. //              extracted. The pointer to the actual data is then extracted  
  143. //              from the _SAFEARRAY pointer.  
  144. //  
  145. // Parameters:  structArray - Array variable.  
  146. //  
  147. // Returns:     POINTER - Pointer to array.  
  148. //  
  149. //////////////////////////////////////////////////////////////////////////////  
  150.   
  151. function POINTER ArrayToPointer(structArray)  
  152.     _SAFEARRAY POINTER pstructArray;    // _SAFEARRAY array pointer  
  153.     _VARIANT   POINTER pstructVariant;  // _VARIANT array pointer  
  154. begin  
  155.     // Typecast the pointer to the array to a _VARIANT pointer.  
  156.       
  157.     pstructVariant = &structArray;  
  158.       
  159.     // Extract the _SAFEARRAY pointer from the _VARIANT.  
  160.       
  161.     pstructArray = pstructVariant->nData;  
  162.       
  163.     // Return the pointer to the actual data from the _SAFEARRAY.  
  164.       
  165.     return pstructArray->pvData;  
  166. end;  
  167.   
  168.   
  169.   
  170. //////////////////////////////////////////////////////////////////////////////  
  171. //  
  172. // Function:    _Process_End  
  173. //  
  174. // Description: Terminates running processes for the specified application.  
  175. //  
  176. // Parameters:  szAppName - Name of the application to terminate.  
  177. //  
  178. // Returns:     >= 0 - Number of processes terminated.  
  179. //                -1 - Failure.  
  180. //  
  181. //////////////////////////////////////////////////////////////////////////////  
  182.   
  183. function NUMBER ProcessEnd(szAppName)  
  184.     NUMBER  nvReturn;           // Number of processes terminated  
  185.     NUMBER  nvProcessIDs(512);  // Array of process IDs  
  186.     NUMBER  nvBytesReturned;    // Number of bytes returned in process ID array  
  187.     NUMBER  nvProcesses;        // Number of processes running  
  188.     NUMBER  nvIndex;            // Loop index  
  189.     NUMBER  nvProcessHandle;    // Handle to a process  
  190.     NUMBER  nvModuleHandle;     // Handle to a process module  
  191.     NUMBER  nvBytesRequired;    // Number of bytes required to store values  
  192.     POINTER pvProcessIDs;       // Pointer to process ID array  
  193.     STRING  svModuleName;       // Module name  
  194.     STRING  svFileName;         // Module filename   
  195. begin  
  196.     // The psapi.dll reads the Windows NT performance database. The DLL  
  197.     // is part of the Win32 SDK.  
  198.       
  199.     if UseDLL(WINSYSDIR ^ PSAPI_FILE) < 0 then  
  200.         // Could not load psapi.dll.  
  201.          
  202.         MessageBox("错误:不能加载文件---[" + WINSYSDIR ^ PSAPI_FILE +  
  203.                 "].", SEVERE);  
  204.          
  205.         return -1;  
  206.     endif;  
  207.       
  208.     // Get the PIDs of all currently running processes.  
  209.       
  210.     pvProcessIDs = ArrayToPointer(nvProcessIDs);  
  211.   
  212.     EnumProcesses(pvProcessIDs, 512, nvBytesReturned);  
  213.   
  214.     // Determine the number of process IDs retrieved. Each process ID  
  215.     // is PROCESSID_LENGTH bytes.  
  216.       
  217.     nvProcesses = nvBytesReturned / PROCESSID_LENGTH;  
  218.       
  219.     // Get the executable associated with each process, and check if  
  220.     // its filename matches the one passed to the function.  
  221.       
  222.     for nvIndex = 1 to nvProcesses  
  223.         // Get a handle to the process. The OpenProcess function  
  224.         // must have full (all) access to be able to terminate  
  225.         // processes.  
  226.          
  227.         nvProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION |  
  228.                 PROCESS_ALL_ACCESS, 0, nvProcessIDs(nvIndex));  
  229.                   
  230.         if nvProcessHandle != 0 then  
  231.             // Get a handle to the first module in the process, which  
  232.             // should be the executable.  
  233.               
  234.             if EnumProcessModules(nvProcessHandle, nvModuleHandle,        
  235.                     PROCESSID_LENGTH, nvBytesRequired) != 0 then  
  236.                 // Get the path of the module.  
  237.                   
  238.                 if GetModuleFileNameExA(nvProcessHandle, nvModuleHandle,  
  239.                         svModuleName, SizeOf(svModuleName)) != 0 then  
  240.                     // Extract the filename (without an extension) from  
  241.                     // the path.  
  242.                      
  243.                     ParsePath(svFileName, svModuleName, FILENAME_ONLY);  
  244.   
  245.                     if StrCompare(svFileName, szAppName) = 0 then  
  246.                         // The process module matches the application   
  247.                         // name passed to the function.  
  248.                           
  249.                         if TerminateProcess(nvProcessHandle, 0) > 0 then  
  250.                             nvReturn++;  
  251.                         endif;  
  252.                     endif;  
  253.                 endif;  
  254.             endif;  
  255.         endif;  
  256.     endfor;  
  257.               
  258.     if UnUseDLL(PSAPI_FILE) < 0 then  
  259.         MessageBox("错误:不能卸载文件---[" + WINSYSDIR ^ PSAPI_FILE +  
  260.                 "].", SEVERE);  
  261.                   
  262.         return -1;  
  263.     endif;  
  264.          
  265.     return nvReturn;  
  266. end;  
  267.   
  268.   
  269.   
  270. //////////////////////////////////////////////////////////////////////////////  
  271. //  
  272. // Function:    _Process_Running  
  273. //  
  274. // Description: Determines if the specified process is running in memory.  
  275. //  
  276. // Parameters:  szAppName - Name of the application to check.  
  277. //  
  278. // Returns:     TRUE  - The process is running.  
  279. //              FALSE - The process is not running.  
  280. //  
  281. //////////////////////////////////////////////////////////////////////////////  
  282.   
  283. function BOOL ProcessRunning(szAppName)  
  284.     BOOL    bvRunning;          // Process is running  
  285.     NUMBER  nvProcessIDs(512);  // Array of process IDs  
  286.     NUMBER  nvBytesReturned;    // Number of bytes returned in process ID array  
  287.     NUMBER  nvProcesses;        // Number of processes running  
  288.     NUMBER  nvIndex;            // Loop index  
  289.     NUMBER  nvProcessHandle;    // Handle to a process  
  290.     NUMBER  nvModuleHandle;     // Handle to a process module  
  291.     NUMBER  nvBytesRequired;    // Number of bytes required to store values  
  292.     POINTER pvProcessIDs;       // Pointer to process ID array  
  293.     STRING  svModuleName;       // Module name  
  294.     STRING  svFileName;         // Module filename   
  295. begin  
  296.     // The psapi.dll reads the Windows NT performance database. The DLL  
  297.     // is part of the Win32 SDK.  
  298.       
  299.     if UseDLL(WINSYSDIR ^ PSAPI_FILE) < 0 then  
  300.         // Could not load psapi.dll.  
  301.          
  302.         MessageBox("错误:不能加载文件---[" + WINSYSDIR ^ PSAPI_FILE +  
  303.                 "].", SEVERE);  
  304.          
  305.         return FALSE;  
  306.     endif;  
  307.       
  308.     // Get the PIDs of all currently running processes.  
  309.       
  310.     pvProcessIDs = ArrayToPointer(nvProcessIDs);  
  311.   
  312.     EnumProcesses(pvProcessIDs, 512, nvBytesReturned);  
  313.   
  314.     // Determine the number of process IDs retrieved. Each process ID  
  315.     // is PROCESSID_LENGTH bytes.  
  316.       
  317.     nvProcesses = nvBytesReturned / PROCESSID_LENGTH;  
  318.       
  319.     // Get the executable associated with each process, and check if  
  320.     // its filename matches the one passed to the function.  
  321.       
  322.     for nvIndex = 1 to nvProcesses  
  323.         // Get a handle to the process.  
  324.          
  325.         nvProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION |  
  326.                 PROCESS_VM_READ, 0, nvProcessIDs(nvIndex));  
  327.                   
  328.         if nvProcessHandle != 0 then  
  329.             // Get a handle to the first module in the process, which  
  330.             // should be the executable.  
  331.               
  332.             if EnumProcessModules(nvProcessHandle, nvModuleHandle,        
  333.                     PROCESSID_LENGTH, nvBytesRequired) != 0 then  
  334.                 // Get the path of the module.  
  335.                   
  336.                 if GetModuleFileNameExA(nvProcessHandle, nvModuleHandle,  
  337.                         svModuleName, SizeOf(svModuleName)) != 0 then  
  338.                     // Extract the filename (without an extension) from  
  339.                     // the path.  
  340.                      
  341.                     ParsePath(svFileName, svModuleName, FILENAME_ONLY);  
  342.                      
  343.                     if StrCompare(svFileName, szAppName) = 0 then  
  344.                         // The process module matches the application   
  345.                         // name passed to the function.  
  346.                           
  347.                         bvRunning = TRUE;  
  348.                           
  349.                         goto ProcessRunningEnd;  
  350.                     endif;  
  351.                 endif;  
  352.             endif;  
  353.         endif;  
  354.     endfor;  
  355.               
  356.     ProcessRunningEnd:  
  357.          
  358.     if UnUseDLL(PSAPI_FILE) < 0 then  
  359.         MessageBox("错误:不能卸载文件---[" + WINSYSDIR ^ PSAPI_FILE +  
  360.                 "].", SEVERE);  
  361.                   
  362.         return FALSE;  
  363.     endif;  
  364.          
  365.     return bvRunning;  
  366. end;  
复制代码
  4、完善InstallShield脚本,实现任意目录的MSDE2000安装。
  修改“featureevents.rul”中的内容为如下代码:
  1. #include "ShutDownRunningApp.rul"  
  2. export prototype DefaultFeature_Installed();  
  3. function DefaultFeature_Installed()  
  4.     number nvServiceState, nResult;  
  5.     string szServiceName, szServiceDisplayName, szServiceDescription, szServicePathFile, szStartServiceArgs;  
  6.     BOOL bStartService;  
  7.     LIST listConnections;  
  8.     string szMsg, szKey, szConnection, szCmdLine;  
  9. begin  
  10.     // 实例名  
  11.     szCmdLine = TARGETDIR^"mssql$fishout";  
  12.     // 转换为短路经  
  13.     LongPathToShortPath(szCmdLine);  
  14.     szCmdLine = "/c  " + szCmdLine + "//Binn//sqlservr.exe -sFISHOUT -c -f -T3608 -T4022";  
  15.     // SQL Server 以单用户模式启动,允许对系统目录进行更新,在新目录附加数据库  
  16.     LaunchApplication(WINSYSDIR ^ "cmd.exe", szCmdLine, "", SW_HIDE, LAAW_OPTION_WAIT, LAAW_OPTION_FIXUP_PROGRAM);  
  17.     // SQL运行时初始化  
  18.     SQLRTInitialize2();  
  19.     // 获取连接信息  
  20.     listConnections = SQLRTGetConnections();  
  21.     ListGetFirstString (listConnections, szConnection);  
  22.     // Windows认证方式  
  23.     SQLRTPutConnectionAuthentication( szConnection, TRUE );  
  24.     // 打开连接  
  25.     nResult = SQLRTConnect( szConnection, "(local)//fishout", TRUE, "", "" );  
  26.     if( nResult < ISERR_SUCCESS ) then  
  27.         // 获取错误信息  
  28.         SQLRTGetErrorMessage( szMsg );  
  29.         // 显示错误信息  
  30.         MessageBox( szMsg, MB_OK );  
  31.     else  
  32.         // SQL Server登录成功,保存连接信息  
  33.         szKey = "";  
  34.         Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_SERVER, szConnection );  
  35.         LogWriteCustomString( szKey, "(local)//fishout" );  
  36.         Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_USER, szConnection );  
  37.         LogWriteCustomString( szKey, "" );  
  38.         Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_AUTH, szConnection );  
  39.         LogWriteCustomNumber( szKey, SQL_AUTH_WINDOWS );  
  40.         Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_DB, szConnection );  
  41.         LogWriteCustomString( szKey, "" );  
  42.     endif;  
  43.     // 执行SQL脚本  
  44.     SQLRTComponentInstall("MSDE2000.sql_SQLComponent");  
  45.     // 中止SQL Server单用户、跟踪进程  
  46.     if ProcessRunning("sqlservr") then  
  47.         ProcessEnd("sqlservr");  
  48.     endif;  
  49.     // 安装SQL Server服务  
  50.     szMsg = "正在启动 MSDE2000 SP4服务......";  
  51.     SdShowMsg(szMsg, TRUE);  
  52.     // 安装服务  
  53.     szServiceName = "MSSQL$FISHOUT";  
  54.     szServiceDisplayName = "MSSQL$FISHOUT";  
  55.     szServiceDescription = "";  
  56.     szServicePathFile = TARGETDIR ^ "mssql$fishout//Binn//sqlservr.exe -sFISHOUT";  
  57.     bStartService = TRUE;  
  58.     szStartServiceArgs = "";  
  59.     if (ServiceGetServiceState (szServiceName, nvServiceState ) >= ISERR_SUCCESS) then  
  60.         // 停止并卸载原来的服务  
  61.         ServiceStopService ( szServiceName );  
  62.         ServiceRemoveService ( szServiceName );  
  63.     endif;  
  64.     ServiceAddService ( szServiceName, szServiceDisplayName, szServiceDescription, szServicePathFile, bStartService, szStartServiceArgs );  
  65.     SdShowMsg(szMsg, FALSE);  
  66. end;  
复制代码
  回到setup.rul脚本中,将下面相关行注释掉,阻止安装过程中出现SQL登录窗口,以便通过脚本程序控制SQL登录和执行SQL脚本,实现任意目录的安装。
  1. Dlg_SQLServer:  
  2.     //nResult = OnSQLServerInitialize( nResult );  
  3.     if( nResult = BACK ) goto Dlg_SdFeatureTree;  
复制代码
  编译并重建安装工程,至此,可以在任意目录下安装的MSDE2000最小版本(仅数据库核心)成功建立,网上的一些绿色MSDE2000版本只需用于应用程序的测试,与应用程序一起集成分发,客户端的安全性可以得到有效保证(微软原始文件),安装包也显得非常专业,当然,实现安装时实例名及sa密码的更改就更理想了,这个问题留待下一步解决。


 在这一节里,我们讨论如何在安装目录的任意指定基础上实现实例名及sa密码的更改,这样,就继承了原有微软80多兆安装包的功能,但是,现有的安装包体积小多了,仅有原来的1/6,当然,这仅是全新安装而言,对于升级安装是不适应的,不过,实际上我们大多数时候都是使用全新安装,何况,MSDE2000还支持多实例安装,所以,这种方法还是非常有实际意义的。
  我们先看看默认实例和命名实例在安装上有何区别:
  1、安装目录的区别;
  默认安装的子目录名称是:C:/Program Files/Microsoft SQL Server/MSSQL/。
  命名实例的子目录名称是:C:/Program Files/Microsoft SQL Server/实例名/。
  2、注册表中的区别:
  默认实例的注册表位置:HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MSSQLServer及Microsoft SQL Server子键。
  命名实例的注册表位置:HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server/实例名。
  看来默认实例和命名实例在安装上无论是目录名还是注册表都还是有很大区别。
  主要设计思路:
  首先,安装子目录的区别可以在Components中的Destination统一设定为,通过自定义窗口根据用户选择用脚本进行控制。
  然而,注册表的区别就没有可以直接设置的地方了,因为,我们先前采用的是注册表导入的方式并与相关Components进行关联这种方式进行的,如果采用脚本写注册表入口的方式实现,固然可行,可是,这个工作量太大了,有没有更为简便的办法来实现呢?通过查询联机帮助,发现,CreateRegistrySet这个注册表函数就可以实现注册表入口与特定component的关联。
  好了,关键问题的解决思路明确了,让我们来具体实现吧!
  目标:实现实例名及sa密码的安装时指定。
  一、注册表准备
  1、如前所述,在运行中浏览至c:/SQL2KSP4/MSDE,让我们以这个命令行安装使用混合模式身份验证的默认实例:setup.exe SECURITYMODE=SQL SAPWD="fishout@TOM.COM" /L*v C:/MSDELog.log,等待安装完毕。
  2、打开注册表编辑器,导航至:HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MSSQLServer,ProtocolList属性中增加tcp/np键值以加快连接速度,删除多余的子健,将MSSQLServer子键下的内容导出,导航至HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server,同样也删除多余的子健并导出,合并两个注册表文件,编辑修改其中的安装路径,使其如下:
  (1)、“默认实例”注册表设置:
  1. Windows Registry Editor Version 5.00  
  2.   
  3. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server]  
  4. "InstalledInstances"=hex(7):4d,00,53,00,53,00,51,00,4c,00,53,00,45,00,52,00,56,/  
  5.   00,45,00,52,00,00,00,00,00  
  6. "SsrpActiveServer"=""  
  7. "SqlMdacRegRefCount"=dword:00000001  
  8.   
  9. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MSSQLServer/MSSQLServer]  
  10. "AuditLevel"=dword:00000000  
  11. "DefaultLogin"="guest"  
  12. "ListenOn"=hex(7):53,00,53,00,4d,00,53,00,53,00,48,00,37,00,30,00,00,00,53,00,/  
  13.   53,00,4e,00,45,00,54,00,4c,00,49,00,42,00,00,00,00,00  
  14. "LoginMode"=dword:00000000  
  15. "Map_"="//"  
  16. "Map#"="-"  
  17. "Map[        DISCUZ_CODE_180        ]quot;=""  
  18. "SetHostName"=dword:00000000  
  19. "Tapeloadwaittime"=dword:ffffffff  
  20. "uptime_pid"=dword:00000e30  
  21. "uptime_time_utc"=hex:de,57,29,6f,c2,5e,ca,01  
  22.   
  23. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MSSQLServer/MSSQLServer/CurrentVersion]  
  24. "CurrentVersion"="8.00.194"  
  25. "RegisteredOwner"=""  
  26. "SerialNumber"=""  
  27. "CSDVersionNumber"=dword:00000400  
  28. "CSDVersion"="8.00.1100"  
  29. "Language"=dword:00000804  
  30. "checksum"=hex:37,38,32,32,63,31,35,38,61,65,37,64,34,63,64,37,35,30,64,61,30,/  
  31.   33,34,62,37,64,63,33,37,66,33,36,33,62,37,36,35,65,35,39,66,37,31,30,32,36,/  
  32.   62,34,37,64,66,36,33,30,63,37,63,64,62,38,64,65,34,37,65,36,30,62,37,32,36,/  
  33.   39,63,36,34,64,31,65,65,38,33,62,33,62,35,35,31,33,61,36,63,64,61,36,66,63,/  
  34.   66,32,65,64,64,39,31,36,62,63,62,39,36,66,34,63,32,61,36,34,34,63,64,64,35,/  
  35.   35,33,34,31,37,36,31,66,62,30,61,64,61,33,32,64,63,64,32,34,39,64,34,31,31,/  
  36.   31,33,38,63,36,38,61,62,31,64,39,63,00  
  37.   
  38. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MSSQLServer/MSSQLServer/Parameters]  
  39. "SQLArg0"="-d//Data//master.mdf"  
  40. "SQLArg1"="-e//LOG//ERRORLOG"  
  41. "SQLArg2"="-l//Data//mastlog.ldf"  
  42.   
  43. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MSSQLServer/MSSQLServer/SuperSocketNetLib]  
  44. "ProtocolList"=hex(7):74,00,63,00,70,00,00,00,6e,00,70,00,00,00,00,00  
  45.   
  46. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MSSQLServer/MSSQLServer/SuperSocketNetLib/Np]  
  47. "PipeName"="////.//pipe////sql//query"  
  48.   
  49. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MSSQLServer/MSSQLServer/SuperSocketNetLib/Tcp]  
  50. "TcpHideFlag"=dword:00000000  
  51. "TcpDynamicPorts"="0"  
  52. "TcpPort"="1433"  
  53.   
  54. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MSSQLServer/Setup]  
  55. "FeatureName"="SqlRun"  
  56. "FirstStart"=dword:00000000  
  57. "ProductCode"="{E09B48B5-E141-427A-AB0C-D3605127224A}"  
  58. "SQLDataRoot"=""  
  59. "SQLPath"=""  
  60. "Edition"="Desktop Engine"  
复制代码
  (2)、“命名实例”注册表设置:
  1. Windows Registry Editor Version 5.00  
  2.   
  3. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server]  
  4. "InstalledInstances"=hex(7):46,00,49,00,53,00,48,00,4f,00,55,00,54,00,00,00,00,/  
  5.   00  
  6. "SsrpActiveServer"=""  
  7. "SqlMdacRegRefCount"=dword:00000001  
  8.   
  9. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server/]  
  10.   
  11. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server//MSSQLServer]  
  12. "AuditLevel"=dword:00000000  
  13. "DefaultLogin"="guest"  
  14. "ListenOn"=hex(7):53,00,53,00,4d,00,53,00,53,00,48,00,37,00,30,00,00,00,53,00,/  
  15.   53,00,4e,00,45,00,54,00,4c,00,49,00,42,00,00,00,00,00  
  16. "LoginMode"=dword:00000000  
  17. "Map_"="//"  
  18. "Map#"="-"  
  19. "Map[        DISCUZ_CODE_181        ]quot;=""  
  20. "SetHostName"=dword:00000000  
  21. "Tapeloadwaittime"=dword:ffffffff  
  22. "uptime_pid"=dword:00000e10  
  23. "uptime_time_utc"=hex:23,ac,f1,ec,70,5f,ca,01  
  24.   
  25. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server//MSSQLServer/CurrentVersion]  
  26. "CurrentVersion"="8.00.194"  
  27. "RegisteredOwner"=""  
  28. "SerialNumber"=""  
  29. "CSDVersionNumber"=dword:00000400  
  30. "CSDVersion"="8.00.1100"  
  31. "Language"=dword:00000804  
  32. "checksum"=hex:37,38,32,32,63,31,35,38,61,65,37,64,34,63,64,37,35,30,64,61,30,/  
  33.   33,34,62,36,30,31,34,32,64,30,61,34,32,61,65,31,37,31,34,33,37,32,63,63,37,/  
  34.   65,30,61,64,31,66,30,31,32,32,33,64,31,66,36,66,30,32,65,31,32,37,63,38,35,/  
  35.   38,64,62,39,35,30,34,31,63,32,66,66,38,30,63,38,37,37,66,34,36,66,61,34,34,/  
  36.   36,32,35,33,33,39,61,38,63,34,62,63,38,36,30,65,31,32,37,66,39,64,34,34,32,/  
  37.   37,36,32,37,39,36,66,31,38,33,30,64,32,64,32,32,30,63,62,66,63,61,64,30,34,/  
  38.   32,30,64,35,63,30,30,33,34,33,65,34,00  
  39.   
  40. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server//MSSQLServer/Parameters]  
  41. "SQLArg0"="-d//Data//master.mdf"  
  42. "SQLArg1"="-e//LOG//ERRORLOG"  
  43. "SQLArg2"="-l//Data//mastlog.ldf"  
  44.   
  45. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server//MSSQLServer/SuperSocketNetLib]  
  46. "ProtocolList"=hex(7):74,00,63,00,70,00,00,00,6e,00,70,00,00,00,00,00  
  47.   
  48. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server//MSSQLServer/SuperSocketNetLib/Np]  
  49. "PipeName"="////.//pipe//MSSQL$FISHOUT//sql//query"  
  50.   
  51. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server//MSSQLServer/SuperSocketNetLib/Tcp]  
  52. "TcpHideFlag"=dword:00000000  
  53. "TcpDynamicPorts"="0"  
  54. "TcpPort"="0"  
  55.   
  56. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server//Setup]  
  57. "FeatureName"="SqlRun"  
  58. "FirstStart"=dword:00000000  
  59. "ProductCode"="{E09B48B5-E141-427A-AB0C-D3605127224A}"  
  60. "SQLDataRoot"=""  
  61. "SQLPath"=""  
  62. "Edition"="Desktop Engine"  
  63. "PatchLevel"="8.4.2039"  
复制代码
  3、在安装工程中,新建注册表入口,重命名为:MDSE2000_Default,右击它,点击:Import REG File...,导入刚才已修改好的“默认实例”注册表设置,再次新建注册表入口,重命名为:MSDE2000_Custom,导入为“命名实例”注册表设置,注意:不要在右边勾选与此关联的安装文件组。
  二、实例名的变更
  实例名的变更通过两个地方进行设置,一是Components的安装路径仅设置为,通过自定义窗口的脚本根据实例名的选择不同而设置不同的路径,二是注册表设置,根据选择的实例名使用CreateRegistrySet函数关联不同的注册表入口。
  三、SA密码的修改方法
  在“MSDE2000.sql”脚本内容中增加一行:exec sp_password NULL, '', 'sa',使其看上去如下:
  1. if not exists (select name from master.dbo.sysdatabases where name = 'model')  
  2. begin  
  3.     exec master..sp_attach_db 'model','C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/model.mdf','C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/modellog.ldf'  
  4.     exec master..sp_attach_db 'msdb','C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/msdbdata.mdf','C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/msdblog.ldf'  
  5.     exec master..sp_resetstatus tempdb  
  6.     Alter database tempdb modify file (name = tempdev, filename = 'C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/tempdb.mdf')  
  7.     Alter database tempdb modify file (name = templog, filename = 'C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/templog.ldf')  
  8.     exec master..sp_password 'fishout@TOM.COM', 'new_password', 'sa'  
  9.     use master  
  10.     exec sp_configure 'allow updates',1  
  11.     reconfigure with override  
  12.     update sysdatabases set [filename]='C:/Program Files/Microsoft SQL Server/MSSQL$FISHOUT/Data/master.mdf' where [name]='master'  
  13.     exec sp_configure 'allow updates',0  
  14.     reconfigure with override  
  15. end  
复制代码
  四、自定义对话框用户接口的实现
  编辑修改原有的SdAskDestPath2对话框,使其如图所示:
mdse2000-3_1.jpg
  将以下自定义对话框脚本另存为:SdAskDestPath2DlgEx.rul,在工程中导入,实现安装路径、实例名和SA密码的设置。
  1. //////////////////////////////////////////////////////////////////////////////////////////  
  2. //  
  3. //  File Name:    SdAskDestPath2DlgEx.rul  
  4. //  
  5. //  Description:  This file contains the InstallShield script for the SdAskDestPath2  
  6. //          dialog function.  
  7. //  
  8. /////////////////////////////////////////////////////////////////////////////////////////  

  9. #include "Dialogs.h"  
  10. #include "CustomDlg.h"  
  11. #include "Winapi.h"  
  12. #include "ISRTDefs.h"  
  13. #include "Silent.h"  
  14. #include "sdrc.h"  
  15. #include "sdint.h"  
  16. #include "DialogsPriv.h"  
  17. // 对话框ID定义  
  18. #define SD_Radio1             1322  
  19. #define SD_Radio2             1323  
  20. #define SD_Text1              1324  
  21. #define SD_Text2              1325  
  22. #define SD_EditInstanceName   1326  
  23. #define SD_EditSaPassword     1327  
  24. prototype SdAskDestPath2Ex(STRING, STRING, BYREF STRING, BYREF STRING, BYREF STRING);  
  25. function SdAskDestPath2Ex(szTitle, szMsg, svDir, svInstanceName, svSaPassword)  
  26.     STRING  szDlg, svDirLoc, szTemp;  
  27.     INT     nId, nTemp, nSdDialog, nStyle;  
  28.     HWND    hwndDlg;  
  29.     BOOL    bDone;  
  30.     STRING  svRadioChoice;  
  31.       
  32.     begin  
  33.     szDlg     = SD_DLG_ASKDESTPATH2;  
  34.     nSdDialog = SD_NDLG_ASKDESTPATH2;  
  35.     svDirLoc = svDir;  
  36.     // 读静默安装参数  
  37.     if (MODE=SILENTMODE) then  
  38.         SdMakeName( szAppKey, szDlg, szTitle, nSdAskDestPath2 );  
  39.         SilentReadData( szAppKey, "Result", DATA_NUMBER, szTemp, nId );  
  40.         if ((nId != BACK) && (nId != CANCEL)) then  
  41.             SilentReadData( szAppKey, "szDir", DATA_STRING, svDir, nTemp );  
  42.             SilentReadData( szAppKey, "szInstanceName", DATA_STRING, svInstanceName, nTemp );  
  43.             SilentReadData( szAppKey, "szSaPassword", DATA_STRING, svSaPassword, nTemp );  
  44.         endif;  
  45.         return nId;  
  46.     endif;  
  47.     // 确保初始化完成  
  48.     if (!bSdInit) then  
  49.         SdInit();  
  50.     endif;  
  51.     if (EzDefineDialog( szDlg, "", "", SD_NDLG_ASKDESTPATH2 ) = DLG_ERR) then  
  52.         return -1;  
  53.     endif;  
  54.     // 循环开始直至用户选择标准按钮  
  55.     bDone = FALSE;  
  56.     while (!bDone)  
  57.        nId = WaitOnDialog( szDlg );  
  58.        switch (nId)  
  59.        case DLG_INIT:  
  60.             hwndDlg = CmdGetHwndDlg( szDlg );  
  61.             TextSubGetValue ( "", svRadioChoice, TRUE, TRUE );  
  62.             if (svRadioChoice = "") then  
  63.           _WinSubEnableControl (hwndDlg, SD_EditInstanceName, 0); // 禁止控件修改  
  64.           CtrlSetState(szDlg, SD_Radio1, BUTTON_CHECKED); // 设置初始状态  
  65.             else  
  66.           CtrlSetState(szDlg, SD_Radio2, BUTTON_CHECKED);  
  67.             endif;  
  68.             TextSubGetValue ( "", svInstanceName, TRUE, TRUE );  
  69.             TextSubGetValue ( "", svSaPassword, TRUE, TRUE );  
  70.             if (svSaPassword = "") then  
  71.           svSaPassword = "fishout@TOM.COM";  
  72.             endif;  
  73.             CtrlSetText(szDlg, SD_EditInstanceName, svInstanceName); // 设置初始值  
  74.             CtrlSetText(szDlg, SD_EditSaPassword, svSaPassword);  
  75.             CtrlSetText( szDlg, 0x80000000 | SD_STA_DESTDIR, svDirLoc );  
  76.             if(szMsg != "") then  
  77.           SdSetStatic( szDlg, SD_STA_CHANGEDIRMSG, szMsg );  
  78.             endif;  
  79.             SdGeneralInit( szDlg, hwndDlg, nStyle, szSdProduct );  
  80.             SdSetDlgTitle(szDlg, hwndDlg, szTitle);  
  81.   
  82.        case SD_Radio1:  
  83.             svRadioChoice = "";  
  84.             svInstanceName = "";  
  85.             svSaPassword = "fishout@TOM.COM";  
  86.             CtrlSetText(szDlg, SD_EditInstanceName, svInstanceName);  
  87.             CtrlSetText(szDlg, SD_EditSaPassword, svSaPassword);  
  88.             _WinSubEnableControl (hwndDlg, SD_EditInstanceName, 0); // 禁止修改  
  89.   
  90.        case SD_Radio2:  
  91.             svRadioChoice = "CustomInstanceName";  
  92.             svInstanceName = "fishout";  
  93.             CtrlSetText(szDlg, SD_EditInstanceName, svInstanceName);  
  94.             _WinSubEnableControl (hwndDlg, SD_EditInstanceName, 1); // 允许修改  
  95.   
  96.        case SD_PBUT_CHANGEDIR:  
  97.             SelectDirNoLog( "", "", svDirLoc, TRUE );  
  98.             CtrlSetText( szDlg, 0x80000000 | SD_STA_DESTDIR, svDirLoc );  
  99.   
  100.        case SD_PBUT_CONTINUE:  
  101.             svDir = svDirLoc;  
  102.             CtrlGetText(szDlg, SD_EditInstanceName, svInstanceName);  
  103.             CtrlGetText(szDlg, SD_EditSaPassword, svSaPassword);  
  104.             StrToUpper(svInstanceName, svInstanceName);  
  105.             TextSubSetValue ( "", svInstanceName, TRUE );  
  106.             TextSubSetValue ( "", svSaPassword, TRUE );  
  107.             TextSubSetValue ( "", svRadioChoice, TRUE );  
  108.             // 根据实例名的不同,确定不同的安装路径  
  109.             if (svRadioChoice = "") then  
  110.           svDir = svDir + "//mssql";  
  111.             else  
  112.           svDir = svDir + "//mssql[        DISCUZ_CODE_183        ]quot; + svInstanceName;  
  113.             endif;  
  114.             nId   = NEXT;  
  115.             bDone = TRUE;  
  116.   
  117.        case BACK:  
  118.             CtrlGetText(szDlg, SD_EditInstanceName, svInstanceName);  
  119.             CtrlGetText(szDlg, SD_EditSaPassword, svSaPassword);  
  120.             TextSubSetValue ( "", svInstanceName, TRUE );  
  121.             TextSubSetValue ( "", svSaPassword, TRUE );  
  122.             TextSubSetValue ( "", svRadioChoice, TRUE );  
  123.             nId    = BACK;  
  124.             bDone  = TRUE;  
  125.   
  126.        case DLG_ERR:  
  127.             SdError( -1, "SdAskDestPath2" );  
  128.             nId   = -1;  
  129.             bDone = TRUE;  
  130.   
  131.        case DLG_CLOSE:  
  132.             SdCloseDlg( hwndDlg, nId, bDone );  
  133.   
  134.        default:  
  135.             // 检查标准按钮句柄  
  136.             if (SdIsStdButton( nId ) && SdDoStdButton( nId )) then  
  137.           bDone = TRUE;  
  138.             endif;  
  139.        endswitch;  
  140.     endwhile;  
  141.     EndDialog( szDlg );  
  142.     ReleaseDialog( szDlg );  
  143.     SdUnInit( );  
  144.     // 保存静默安装参数  
  145.     if (MODE=RECORDMODE) then  
  146.         SdMakeName( szAppKey, szDlg, szTitle, nSdAskDestPath2 );  
  147.         SilentWriteData( szAppKey, "szDir", DATA_STRING, svDir, 0 );  
  148.         SilentWriteData( szAppKey, "szInstanceName", DATA_STRING, svInstanceName, 0 );  
  149.         SilentWriteData( szAppKey, "szSaPassword", DATA_STRING, svSaPassword, 0 );  
  150.         SilentWriteData( szAppKey, "Result", DATA_NUMBER, "", nId );  
  151.     endif;  
  152.     return nId;  
  153.     end;  
复制代码
  五、修改脚本文件
  1、将Setup.rul中Dlg_SdAskDestPath2标号处的内容修改为以下代码:
  1. Dlg_SdAskDestPath2:  
  2.     if ((nResult = BACK) && (nSetupType != CUSTOM)) goto Dlg_SetupType2;  
  3.     szTitle = "";  
  4.     szMsg = "";  
  5.     // 还原保存的路径,用于自定义对话框  
  6.     szDir = szCustomDir;  
  7.     if (nSetupType = CUSTOM) then  
  8.                 //{{IS_SCRIPT_TAG(Dlg_SdAskDestPath2)     
  9.         nResult = SdAskDestPath2Ex( szTitle, szMsg, szDir, svInstanceName, svSaPassword );  
  10.                 //}}IS_SCRIPT_TAG(Dlg_SdAskDestPath2)  
  11.         TARGETDIR = szDir;  
  12.     else  
  13.         TARGETDIR = szDir + "//mssql";  
  14.         svInstanceName = "";  
  15.         svSaPassword = "fishout@TOM.COM";  
  16.     endif;  
  17.     if (nResult = BACK) goto Dlg_SetupType2;  
复制代码
  2、修改“featureevents.rul”中的内容,实现注册表入口关联及SQL脚本的执行,代码如下:
  1. //---------------------------------------------------------------------------  
  2. // The Installed event is sent after the feature DefaultFeature  
  3. // is installed.  
  4. //---------------------------------------------------------------------------  
  5.   
  6. #include "ShutDownRunningApp.rul"  
  7. export prototype DefaultFeature_Installed();  
  8. function DefaultFeature_Installed()  
  9.     number nvServiceState, nResult;  
  10.     string szServiceName, szServiceDisplayName, szServiceDescription, szServicePathFile, szStartServiceArgs;  
  11.     BOOL bStartService;  
  12.     LIST listConnections;  
  13.     string szMsg, szKey, szConnection, szCmdLine, szServer, svInstanceName;  
  14. begin  
  15.     szCmdLine = TARGETDIR ^ "Binn//sqlservr.exe";  
  16.     // 转换为短路经  
  17.     LongPathToShortPath(szCmdLine);  
  18.     // 实例名  
  19.     TextSubGetValue ( "", svInstanceName, TRUE, TRUE );  
  20.     if (svInstanceName = "") then  
  21.         szServer = "(local)";  
  22.         szServiceName = "MSSQLSERVER";  
  23.         szServiceDisplayName = "MSSQLSERVER";  
  24.         szServicePathFile = TARGETDIR ^ "Binn//sqlservr.exe -sMSSQLSERVER";  
  25.         szCmdLine = "/c " + szCmdLine + " -sMSSQLSERVER -c -f -T3608 -T4022";  
  26.         CreateRegistrySet("MSDE2000_Default"); // 写注册表入口  
  27.     else  
  28.         szServer = "(local)//" + svInstanceName;  
  29.         szServiceName = "MSSQL[        DISCUZ_CODE_185        ]quot; + svInstanceName;  
  30.         szServiceDisplayName = szServiceName;  
  31.         szServicePathFile = TARGETDIR ^ "Binn//sqlservr.exe -s" + svInstanceName;  
  32.         szCmdLine = "/c " + szCmdLine + " -s" + svInstanceName + " -c -f -T3608 -T4022";  
  33.         CreateRegistrySet("MSDE2000_Custom");  
  34.     endif;  
  35.     // SQL Server 以单用户模式启动,允许对系统目录进行更新,在新目录附加[color=#df3434][b][url=http://lib.csdn.net/base/mysql]数据库[/url][/b][/color]  
  36.     LaunchApplication(WINSYSDIR ^ "cmd.exe", szCmdLine, "", SW_HIDE, LAAW_OPTION_WAIT, LAAW_OPTION_FIXUP_PROGRAM);  
  37.     // SQL运行时初始化  
  38.     SQLRTInitialize2();  
  39.     // 获取连接信息  
  40.     listConnections = SQLRTGetConnections();  
  41.     ListGetFirstString (listConnections, szConnection);  
  42.     // Windows认证方式  
  43.     SQLRTPutConnectionAuthentication( szConnection, TRUE );  
  44.     // 打开连接  
  45.     nResult = SQLRTConnect( szConnection, szServer, TRUE, "", "" );  
  46.     if( nResult < ISERR_SUCCESS ) then  
  47.         // 获取错误信息  
  48.         SQLRTGetErrorMessage( szMsg );  
  49.         // 显示错误信息  
  50.         MessageBox( szMsg, MB_OK );  
  51.     else  
  52.         // SQL Server登录成功,保存连接信息  
  53.         szKey = "";  
  54.         Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_SERVER, szConnection );  
  55.         LogWriteCustomString( szKey, szServer );  
  56.         Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_USER, szConnection );  
  57.         LogWriteCustomString( szKey, "" );  
  58.         Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_AUTH, szConnection );  
  59.         LogWriteCustomNumber( szKey, SQL_AUTH_WINDOWS );  
  60.         Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_DB, szConnection );  
  61.         LogWriteCustomString( szKey, "" );  
  62.     endif;  
  63.     // 执行SQL脚本  
  64.     SQLRTComponentInstall("MSDE2000.sql_SQLComponent");  
  65.     // 中止SQL Server单用户、跟踪进程  
  66.     if ProcessRunning("sqlservr") then  
  67.         ProcessEnd("sqlservr");  
  68.     endif;  
  69.     // 安装SQL Server服务  
  70.     szMsg = "正在启动 MSDE2000 SP4服务......";  
  71.     SdShowMsg(szMsg, TRUE);  
  72.     // 安装服务  
  73.     szServiceDescription = "";  
  74.     bStartService = TRUE;  
  75.     szStartServiceArgs = "";  
  76.     if (ServiceGetServiceState (szServiceName, nvServiceState ) >= ISERR_SUCCESS) then  
  77.         // 停止并卸载原来的服务  
  78.         ServiceStopService ( szServiceName );  
  79.         ServiceRemoveService ( szServiceName );  
  80.     endif;  
  81.     ServiceAddService ( szServiceName, szServiceDisplayName, szServiceDescription, szServicePathFile, bStartService, szStartServiceArgs );  
  82.     SdShowMsg(szMsg, FALSE);  
  83. end;  
复制代码
  好了!一个相对比较完美的MSDE2000最小版本就实现了,这下可以将其集成在自己的应用程序中,以下问题全部解决:
    1、无法与应用程序的安装一并卸载;
    2、无法实现MSDE2000的最小安装;
    3、如果用户中途取消安装,程序不能完全回滚;
    4、无法与应用程序安装到同一个目录。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|手机版|Archiver|SgzyStudio

GMT+8, 2024-5-19 20:25 , Processed in 0.113346 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表