首页 > 代码库 > InstallShield集成安装MSDE2000最小版本(二) fishout特许授权发布

InstallShield集成安装MSDE2000最小版本(二) fishout特许授权发布

原文:InstallShield集成安装MSDE2000最小版本(二) fishout特许授权发布

原帖地址:http://blog.csdn.net/fishout/archive/2009/10/28/4739269.aspx

在这一节里,我们解决安装路径的更改问题。大家知道,MSDE2000安装后,数据库路径不能更改,这也是制约许多安装包无法与应用程序一并集成的首要原因,现在我们来解决这一个问题。
  主要思路是通过分离msdb和model数据库,然后更改master数据库的系统目录指向,改为相对目录,最后,通过附加msdb及model并重建tempdb数据库来实现。
  目标:实现集成包的任意目录安装。
  注意:以下操作在前一节基础上继续。
  一、准备数据库
  1、启动先前安装的MSDE2000服务;
  2、使用命令行工具分离并修改系统数据库;
  3、将下面SQL脚本内容保存至:C:\Program Files\Microsoft SQL Server\80\Tools\Binn,文件名命名为:detach.sql。

view plaincopy to clipboardprint?

  1. use master   
  2. go   
  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 

use master go sp_configure ‘allow updates‘,1 go reconfigure with override go update sysaltfiles set [filename]=‘.\..\data\master.mdf‘ where [name]=‘master‘ update sysaltfiles set [filename]=‘.\..\data\mastlog.ldf‘ where [name]=‘mastlog‘ update sysdatabases set [filename]=‘.\..\data\master.mdf‘ where [name]=‘master‘ go sp_detach_db ‘msdb‘ go sp_detach_db ‘model‘ go sp_configure ‘allow updates‘,0 go reconfigure with override 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,执行相对目录更改及分离操作,操作成功后会出现如下画面:图一
  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...”按钮添加一条替换记录,以便实现安装路径的变换,如图:图二

view plaincopy to clipboardprint?

  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 

if not exists (select name from master.dbo.sysdatabases where name = ‘model‘) begin 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‘ 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‘ exec master..sp_resetstatus tempdb Alter database tempdb modify file (name = tempdev, filename = ‘C:\Program Files\Microsoft SQL Server\MSSQL$FISHOUT\Data\tempdb.mdf‘) Alter database tempdb modify file (name = templog, filename = ‘C:\Program Files\Microsoft SQL Server\MSSQL$FISHOUT\Data\templog.ldf‘) end
  3、导入进程中止脚本。
  引用前人已写的现成脚本,将以下脚本内容保存至:工程文件夹下的“Script Files”子文件夹中,文件名为:ShutDownRunningApp.rul,单击面板中“InstallScript”,右击“Files”,选择“Insert Script Files...”,浏览至工程文件夹下的“Script Files”子文件夹,将“ShutDownRunningApp.rul”脚本导入,需要使用这个脚本来实现SQL进程的中止。

view plaincopy to clipboardprint?

  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 www.installsite.org. 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 (riwasa@email.com).
  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: bsnodgrass@geographix.com
  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. // Function prototypes.
  65. /////////////////////////////////////////////////
  66. prototype POINTER ArrayToPointer(BYREF VARIANT);   
  67. prototype NUMBER  ProcessEnd(STRING);   
  68. prototype BOOL    ProcessRunning(STRING);   
  69. // Kernel functions.
  70. prototype NUMBER Kernel32.OpenProcess(NUMBER, BOOL, NUMBER);   
  71. prototype NUMBER Kernel32.TerminateProcess(NUMBER, NUMBER);   
  72. // Process information functions.
  73. prototype NUMBER PSAPI.EnumProcesses(POINTER, NUMBER, BYREF NUMBER);   
  74. prototype NUMBER PSAPI.EnumProcessModules(NUMBER, BYREF NUMBER, NUMBER,   
  75.         BYREF NUMBER);   
  76. prototype NUMBER PSAPI.GetModuleFileNameExA(NUMBER, NUMBER, BYREF STRING,   
  77.         NUMBER);   
  78. /////////////////////////////////////////////////
  79. // Structures.
  80. /////////////////////////////////////////////////
  81. // Structure to mirror the C/C++ SAFEARRAY data structure.
  82. typedef _SAFEARRAY   
  83. begin   
  84.     SHORT   cDims;   
  85.     SHORT   fFeatures;   
  86.     LONG    cbElements;   
  87.     LONG    cLocks;   
  88.     POINTER pvData;   
  89. // rgsaBound omitted
  90. end;   
  91. // Structure to mirror the C/C++ VARIANT data structure.
  92. typedef _VARIANT   
  93. begin   
  94.     SHORT  vt;   
  95.     SHORT  wReserver1;   
  96.     SHORT  wReserved2;   
  97.     SHORT  wReserved3;   
  98.     NUMBER nData;   
  99. end;   
  100. /////////////////////////////////////////////////
  101. // Constants.
  102. /////////////////////////////////////////////////
  103. #define PSAPI_FILE        "psapi.dll"  // Windows NT process DLL
  104. #define PROCESSID_LENGTH  4            // 4 bytes (DWORD) for a process ID
  105. // Process information constants.
  106. #define PROCESS_QUERY_INFORMATION  0x400
  107. #define PROCESS_ALL_ACCESS         0x1f0fff
  108. #define PROCESS_VM_READ            0x10
  109. //////////////////////////////////////////////////////////////////////////////
  110. //
  111. // Function:    ArrayToPointer
  112. //
  113. // Description: Converts an InstallShield array into a C array.
  114. //
  115. //              When an array is created in InstallScript, a VARIANT variable
  116. //              is created which holds an OLEAutomation SAFEARRAY. To pass
  117. //              such an array to a DLL function expecting a C-style array,
  118. //              this function explicitly typecasts the pointer to the array
  119. //              to a _VARIANT pointer so that the _SAFEARRAY pointer can be
  120. //              extracted. The pointer to the actual data is then extracted
  121. //              from the _SAFEARRAY pointer.
  122. //
  123. // Parameters:  structArray - Array variable.
  124. //
  125. // Returns:     POINTER - Pointer to array.
  126. //
  127. //////////////////////////////////////////////////////////////////////////////
  128. function POINTER ArrayToPointer(structArray)   
  129.     _SAFEARRAY POINTER pstructArray;    // _SAFEARRAY array pointer
  130.     _VARIANT   POINTER pstructVariant;  // _VARIANT array pointer
  131. begin   
  132. // Typecast the pointer to the array to a _VARIANT pointer.
  133.     pstructVariant = &structArray;   
  134. // Extract the _SAFEARRAY pointer from the _VARIANT.
  135.     pstructArray = pstructVariant->nData;   
  136. // Return the pointer to the actual data from the _SAFEARRAY.
  137. return pstructArray->pvData;   
  138. end;   
  139. //////////////////////////////////////////////////////////////////////////////
  140. //
  141. // Function:    _Process_End
  142. //
  143. // Description: Terminates running processes for the specified application.
  144. //
  145. // Parameters:  szAppName - Name of the application to terminate.
  146. //
  147. // Returns:     >= 0 - Number of processes terminated.
  148. //                -1 - Failure.
  149. //
  150. //////////////////////////////////////////////////////////////////////////////
  151. function NUMBER ProcessEnd(szAppName)   
  152.     NUMBER  nvReturn;           // Number of processes terminated
  153.     NUMBER  nvProcessIDs(512);  // Array of process IDs
  154.     NUMBER  nvBytesReturned;    // Number of bytes returned in process ID array
  155.     NUMBER  nvProcesses;        // Number of processes running
  156.     NUMBER  nvIndex;            // Loop index
  157.     NUMBER  nvProcessHandle;    // Handle to a process
  158.     NUMBER  nvModuleHandle;     // Handle to a process module
  159.     NUMBER  nvBytesRequired;    // Number of bytes required to store values
  160.     POINTER pvProcessIDs;       // Pointer to process ID array
  161.     STRING  svModuleName;       // Module name
  162.     STRING  svFileName;         // Module filename 
  163. begin   
  164. // The psapi.dll reads the Windows NT performance database. The DLL
  165. // is part of the Win32 SDK.
  166. if UseDLL(WINSYSDIR ^ PSAPI_FILE) < 0 then   
  167. // Could not load psapi.dll.
  168.         MessageBox("错误:不能加载文件---[" + WINSYSDIR ^ PSAPI_FILE +   
  169. "].", SEVERE);   
  170. return -1;   
  171.     endif;   
  172. // Get the PIDs of all currently running processes.
  173.     pvProcessIDs = ArrayToPointer(nvProcessIDs);   
  174.     EnumProcesses(pvProcessIDs, 512, nvBytesReturned);   
  175. // Determine the number of process IDs retrieved. Each process ID
  176. // is PROCESSID_LENGTH bytes.
  177.     nvProcesses = nvBytesReturned / PROCESSID_LENGTH;   
  178. // Get the executable associated with each process, and check if
  179. // its filename matches the one passed to the function.
  180. for nvIndex = 1 to nvProcesses   
  181. // Get a handle to the process. The OpenProcess function
  182. // must have full (all) access to be able to terminate
  183. // processes.
  184.         nvProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION |   
  185.                 PROCESS_ALL_ACCESS, 0, nvProcessIDs(nvIndex));   
  186. if nvProcessHandle != 0 then   
  187. // Get a handle to the first module in the process, which
  188. // should be the executable.
  189. if EnumProcessModules(nvProcessHandle, nvModuleHandle,         
  190.                     PROCESSID_LENGTH, nvBytesRequired) != 0 then   
  191. // Get the path of the module.
  192. if GetModuleFileNameExA(nvProcessHandle, nvModuleHandle,   
  193.                         svModuleName, SizeOf(svModuleName)) != 0 then   
  194. // Extract the filename (without an extension) from
  195. // the path.
  196.                     ParsePath(svFileName, svModuleName, FILENAME_ONLY);   
  197. if StrCompare(svFileName, szAppName) = 0 then   
  198. // The process module matches the application 
  199. // name passed to the function.
  200. if TerminateProcess(nvProcessHandle, 0) > 0 then   
  201.                             nvReturn++;   
  202.                         endif;   
  203.                     endif;   
  204.                 endif;   
  205.             endif;   
  206.         endif;   
  207.     endfor;   
  208. if UnUseDLL(PSAPI_FILE) < 0 then   
  209.         MessageBox("错误:不能卸载文件---[" + WINSYSDIR ^ PSAPI_FILE +   
  210. "].", SEVERE);   
  211. return -1;   
  212.     endif;   
  213. return nvReturn;   
  214. end;   
  215. //////////////////////////////////////////////////////////////////////////////
  216. //
  217. // Function:    _Process_Running
  218. //
  219. // Description: Determines if the specified process is running in memory.
  220. //
  221. // Parameters:  szAppName - Name of the application to check.
  222. //
  223. // Returns:     TRUE  - The process is running.
  224. //              FALSE - The process is not running.
  225. //
  226. //////////////////////////////////////////////////////////////////////////////
  227. function BOOL ProcessRunning(szAppName)   
  228.     BOOL    bvRunning;          // Process is running
  229.     NUMBER  nvProcessIDs(512);  // Array of process IDs
  230.     NUMBER  nvBytesReturned;    // Number of bytes returned in process ID array
  231.     NUMBER  nvProcesses;        // Number of processes running
  232.     NUMBER  nvIndex;            // Loop index
  233.     NUMBER  nvProcessHandle;    // Handle to a process
  234.     NUMBER  nvModuleHandle;     // Handle to a process module
  235.     NUMBER  nvBytesRequired;    // Number of bytes required to store values
  236.     POINTER pvProcessIDs;       // Pointer to process ID array
  237.     STRING  svModuleName;       // Module name
  238.     STRING  svFileName;         // Module filename 
  239. begin   
  240. // The psapi.dll reads the Windows NT performance database. The DLL
  241. // is part of the Win32 SDK.
  242. if UseDLL(WINSYSDIR ^ PSAPI_FILE) < 0 then   
  243. // Could not load psapi.dll.
  244.         MessageBox("错误:不能加载文件---[" + WINSYSDIR ^ PSAPI_FILE +   
  245. "].", SEVERE);   
  246. return FALSE;   
  247.     endif;   
  248. // Get the PIDs of all currently running processes.
  249.     pvProcessIDs = ArrayToPointer(nvProcessIDs);   
  250.     EnumProcesses(pvProcessIDs, 512, nvBytesReturned);   
  251. // Determine the number of process IDs retrieved. Each process ID
  252. // is PROCESSID_LENGTH bytes.
  253.     nvProcesses = nvBytesReturned / PROCESSID_LENGTH;   
  254. // Get the executable associated with each process, and check if
  255. // its filename matches the one passed to the function.
  256. for nvIndex = 1 to nvProcesses   
  257. // Get a handle to the process.
  258.         nvProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION |   
  259.                 PROCESS_VM_READ, 0, nvProcessIDs(nvIndex));   
  260. if nvProcessHandle != 0 then   
  261. // Get a handle to the first module in the process, which
  262. // should be the executable.
  263. if EnumProcessModules(nvProcessHandle, nvModuleHandle,         
  264.                     PROCESSID_LENGTH, nvBytesRequired) != 0 then   
  265. // Get the path of the module.
  266. if GetModuleFileNameExA(nvProcessHandle, nvModuleHandle,   
  267.                         svModuleName, SizeOf(svModuleName)) != 0 then   
  268. // Extract the filename (without an extension) from
  269. // the path.
  270.                     ParsePath(svFileName, svModuleName, FILENAME_ONLY);   
  271. if StrCompare(svFileName, szAppName) = 0 then   
  272. // The process module matches the application 
  273. // name passed to the function.
  274.                         bvRunning = TRUE;   
  275. goto ProcessRunningEnd;   
  276.                     endif;   
  277.                 endif;   
  278.             endif;   
  279.         endif;   
  280.     endfor;   
  281.     ProcessRunningEnd:   
  282. if UnUseDLL(PSAPI_FILE) < 0 then   
  283.         MessageBox("错误:不能卸载文件---[" + WINSYSDIR ^ PSAPI_FILE +   
  284. "].", SEVERE);   
  285. return FALSE;   
  286.     endif;   
  287. return bvRunning;   
  288. end; 

////////////////////////////////////////////////////////////////////////////// // // Description: Windows NT process control functions. // // The process code is adapted from code posted by William F. // Snodgrass to www.installsite.org. The original code header // is appended below. The array code is adapted from code posted // by Rajesh Ramachandran to the installshield.is6.installscript // newsgroup. // // Submitted by Richard Iwasa (riwasa@email.com). // // Usage example: // // if ProcessRunning("notepad") then // MessageBox("Application is running.", INFORMATION); // // ProcessEnd("notepad"); // // Delay(2); // Delay to allow process list to refresh // // if ProcessRunning("notepad") then // MessageBox("Application is running.", INFORMATION); // else // MessageBox("Application is not running.", INFORMATION); // endif; // else // MessageBox("Application is not running.", INFORMATION); // endif; // // Original code header appended below: // // GetRunningApp(); // ShutDownApp(); // // These script created functions will look for any running application // based on the file name, then display an error message within the Setup. // You can optionally halt the install or just continue on. // // You can use the ShutDownApp() function for shutting down that process // or others as well. This is useful for processes that run in the // background but have no Windows associated with them. May not work with // Services. // // This script calls functions in PSAPI.DLL that are not supported on // Windows 95 or 98. // // ***Instructions*** // Place these script peices into the Setup.rul file. // // Modify the script to include the applications you would like to get or // shutdown. // // Submitted by William F. Snodgrass // Contact info: bsnodgrass@geographix.com // // Created by Theron Welch, 3/3/99 // Minor modifications by Stefan Krueger, 11/03/99 // // Copyright (c) 1999-2000 GeoGraphix, Inc. // ////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////// // Function prototypes. ///////////////////////////////////////////////// prototype POINTER ArrayToPointer(BYREF VARIANT); prototype NUMBER ProcessEnd(STRING); prototype BOOL ProcessRunning(STRING); // Kernel functions. prototype NUMBER Kernel32.OpenProcess(NUMBER, BOOL, NUMBER); prototype NUMBER Kernel32.TerminateProcess(NUMBER, NUMBER); // Process information functions. prototype NUMBER PSAPI.EnumProcesses(POINTER, NUMBER, BYREF NUMBER); prototype NUMBER PSAPI.EnumProcessModules(NUMBER, BYREF NUMBER, NUMBER, BYREF NUMBER); prototype NUMBER PSAPI.GetModuleFileNameExA(NUMBER, NUMBER, BYREF STRING, NUMBER); ///////////////////////////////////////////////// // Structures. ///////////////////////////////////////////////// // Structure to mirror the C/C++ SAFEARRAY data structure. typedef _SAFEARRAY begin SHORT cDims; SHORT fFeatures; LONG cbElements; LONG cLocks; POINTER pvData; // rgsaBound omitted end; // Structure to mirror the C/C++ VARIANT data structure. typedef _VARIANT begin SHORT vt; SHORT wReserver1; SHORT wReserved2; SHORT wReserved3; NUMBER nData; end; ///////////////////////////////////////////////// // Constants. ///////////////////////////////////////////////// #define PSAPI_FILE "psapi.dll" // Windows NT process DLL #define PROCESSID_LENGTH 4 // 4 bytes (DWORD) for a process ID // Process information constants. #define PROCESS_QUERY_INFORMATION 0x400 #define PROCESS_ALL_ACCESS 0x1f0fff #define PROCESS_VM_READ 0x10 ////////////////////////////////////////////////////////////////////////////// // // Function: ArrayToPointer // // Description: Converts an InstallShield array into a C array. // // When an array is created in InstallScript, a VARIANT variable // is created which holds an OLEAutomation SAFEARRAY. To pass // such an array to a DLL function expecting a C-style array, // this function explicitly typecasts the pointer to the array // to a _VARIANT pointer so that the _SAFEARRAY pointer can be // extracted. The pointer to the actual data is then extracted // from the _SAFEARRAY pointer. // // Parameters: structArray - Array variable. // // Returns: POINTER - Pointer to array. // ////////////////////////////////////////////////////////////////////////////// function POINTER ArrayToPointer(structArray) _SAFEARRAY POINTER pstructArray; // _SAFEARRAY array pointer _VARIANT POINTER pstructVariant; // _VARIANT array pointer begin // Typecast the pointer to the array to a _VARIANT pointer. pstructVariant = &structArray; // Extract the _SAFEARRAY pointer from the _VARIANT. pstructArray = pstructVariant->nData; // Return the pointer to the actual data from the _SAFEARRAY. return pstructArray->pvData; end; ////////////////////////////////////////////////////////////////////////////// // // Function: _Process_End // // Description: Terminates running processes for the specified application. // // Parameters: szAppName - Name of the application to terminate. // // Returns: >= 0 - Number of processes terminated. // -1 - Failure. // ////////////////////////////////////////////////////////////////////////////// function NUMBER ProcessEnd(szAppName) NUMBER nvReturn; // Number of processes terminated NUMBER nvProcessIDs(512); // Array of process IDs NUMBER nvBytesReturned; // Number of bytes returned in process ID array NUMBER nvProcesses; // Number of processes running NUMBER nvIndex; // Loop index NUMBER nvProcessHandle; // Handle to a process NUMBER nvModuleHandle; // Handle to a process module NUMBER nvBytesRequired; // Number of bytes required to store values POINTER pvProcessIDs; // Pointer to process ID array STRING svModuleName; // Module name STRING svFileName; // Module filename begin // The psapi.dll reads the Windows NT performance database. The DLL // is part of the Win32 SDK. if UseDLL(WINSYSDIR ^ PSAPI_FILE) < 0 then // Could not load psapi.dll. MessageBox("错误:不能加载文件---[" + WINSYSDIR ^ PSAPI_FILE + "].", SEVERE); return -1; endif; // Get the PIDs of all currently running processes. pvProcessIDs = ArrayToPointer(nvProcessIDs); EnumProcesses(pvProcessIDs, 512, nvBytesReturned); // Determine the number of process IDs retrieved. Each process ID // is PROCESSID_LENGTH bytes. nvProcesses = nvBytesReturned / PROCESSID_LENGTH; // Get the executable associated with each process, and check if // its filename matches the one passed to the function. for nvIndex = 1 to nvProcesses // Get a handle to the process. The OpenProcess function // must have full (all) access to be able to terminate // processes. nvProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_ALL_ACCESS, 0, nvProcessIDs(nvIndex)); if nvProcessHandle != 0 then // Get a handle to the first module in the process, which // should be the executable. if EnumProcessModules(nvProcessHandle, nvModuleHandle, PROCESSID_LENGTH, nvBytesRequired) != 0 then // Get the path of the module. if GetModuleFileNameExA(nvProcessHandle, nvModuleHandle, svModuleName, SizeOf(svModuleName)) != 0 then // Extract the filename (without an extension) from // the path. ParsePath(svFileName, svModuleName, FILENAME_ONLY); if StrCompare(svFileName, szAppName) = 0 then // The process module matches the application // name passed to the function. if TerminateProcess(nvProcessHandle, 0) > 0 then nvReturn++; endif; endif; endif; endif; endif; endfor; if UnUseDLL(PSAPI_FILE) < 0 then MessageBox("错误:不能卸载文件---[" + WINSYSDIR ^ PSAPI_FILE + "].", SEVERE); return -1; endif; return nvReturn; end; ////////////////////////////////////////////////////////////////////////////// // // Function: _Process_Running // // Description: Determines if the specified process is running in memory. // // Parameters: szAppName - Name of the application to check. // // Returns: TRUE - The process is running. // FALSE - The process is not running. // ////////////////////////////////////////////////////////////////////////////// function BOOL ProcessRunning(szAppName) BOOL bvRunning; // Process is running NUMBER nvProcessIDs(512); // Array of process IDs NUMBER nvBytesReturned; // Number of bytes returned in process ID array NUMBER nvProcesses; // Number of processes running NUMBER nvIndex; // Loop index NUMBER nvProcessHandle; // Handle to a process NUMBER nvModuleHandle; // Handle to a process module NUMBER nvBytesRequired; // Number of bytes required to store values POINTER pvProcessIDs; // Pointer to process ID array STRING svModuleName; // Module name STRING svFileName; // Module filename begin // The psapi.dll reads the Windows NT performance database. The DLL // is part of the Win32 SDK. if UseDLL(WINSYSDIR ^ PSAPI_FILE) < 0 then // Could not load psapi.dll. MessageBox("错误:不能加载文件---[" + WINSYSDIR ^ PSAPI_FILE + "].", SEVERE); return FALSE; endif; // Get the PIDs of all currently running processes. pvProcessIDs = ArrayToPointer(nvProcessIDs); EnumProcesses(pvProcessIDs, 512, nvBytesReturned); // Determine the number of process IDs retrieved. Each process ID // is PROCESSID_LENGTH bytes. nvProcesses = nvBytesReturned / PROCESSID_LENGTH; // Get the executable associated with each process, and check if // its filename matches the one passed to the function. for nvIndex = 1 to nvProcesses // Get a handle to the process. nvProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, nvProcessIDs(nvIndex)); if nvProcessHandle != 0 then // Get a handle to the first module in the process, which // should be the executable. if EnumProcessModules(nvProcessHandle, nvModuleHandle, PROCESSID_LENGTH, nvBytesRequired) != 0 then // Get the path of the module. if GetModuleFileNameExA(nvProcessHandle, nvModuleHandle, svModuleName, SizeOf(svModuleName)) != 0 then // Extract the filename (without an extension) from // the path. ParsePath(svFileName, svModuleName, FILENAME_ONLY); if StrCompare(svFileName, szAppName) = 0 then // The process module matches the application // name passed to the function. bvRunning = TRUE; goto ProcessRunningEnd; endif; endif; endif; endif; endfor; ProcessRunningEnd: if UnUseDLL(PSAPI_FILE) < 0 then MessageBox("错误:不能卸载文件---[" + WINSYSDIR ^ PSAPI_FILE + "].", SEVERE); return FALSE; endif; return bvRunning; end;
  4、完善InstallShield脚本,实现任意目录的MSDE2000安装。
  修改“featureevents.rul”中的内容为如下代码:

view plaincopy to clipboardprint?

  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; 

#include "ShutDownRunningApp.rul" export prototype DefaultFeature_Installed(); function DefaultFeature_Installed() number nvServiceState, nResult; string szServiceName, szServiceDisplayName, szServiceDescription, szServicePathFile, szStartServiceArgs; BOOL bStartService; LIST listConnections; string szMsg, szKey, szConnection, szCmdLine; begin // 实例名 szCmdLine = TARGETDIR^"mssql$fishout"; // 转换为短路经 LongPathToShortPath(szCmdLine); szCmdLine = "/c " + szCmdLine + "\\Binn\\sqlservr.exe -sFISHOUT -c -f -T3608 -T4022"; // SQL Server 以单用户模式启动,允许对系统目录进行更新,在新目录附加数据库 LaunchApplication(WINSYSDIR ^ "cmd.exe", szCmdLine, "", SW_HIDE, LAAW_OPTION_WAIT, LAAW_OPTION_FIXUP_PROGRAM); // SQL运行时初始化 SQLRTInitialize2(); // 获取连接信息 listConnections = SQLRTGetConnections(); ListGetFirstString (listConnections, szConnection); // Windows认证方式 SQLRTPutConnectionAuthentication( szConnection, TRUE ); // 打开连接 nResult = SQLRTConnect( szConnection, "(local)\\fishout", TRUE, "", "" ); if( nResult < ISERR_SUCCESS ) then // 获取错误信息 SQLRTGetErrorMessage( szMsg ); // 显示错误信息 MessageBox( szMsg, MB_OK ); else // SQL Server登录成功,保存连接信息 szKey = ""; Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_SERVER, szConnection ); LogWriteCustomString( szKey, "(local)\\fishout" ); Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_USER, szConnection ); LogWriteCustomString( szKey, "" ); Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_AUTH, szConnection ); LogWriteCustomNumber( szKey, SQL_AUTH_WINDOWS ); Sprintf( szKey, SQL_FORMATSTRING_CONNECTION_DB, szConnection ); LogWriteCustomString( szKey, "" ); endif; // 执行SQL脚本 SQLRTComponentInstall("MSDE2000.sql_SQLComponent"); // 中止SQL Server单用户、跟踪进程 if ProcessRunning("sqlservr") then ProcessEnd("sqlservr"); endif; // 安装SQL Server服务 szMsg = "正在启动 MSDE2000 SP4服务......"; SdShowMsg(szMsg, TRUE); // 安装服务 szServiceName = "MSSQL$FISHOUT"; szServiceDisplayName = "MSSQL$FISHOUT"; szServiceDescription = ""; szServicePathFile = TARGETDIR ^ "mssql$fishout\\Binn\\sqlservr.exe -sFISHOUT"; bStartService = TRUE; szStartServiceArgs = ""; if (ServiceGetServiceState (szServiceName, nvServiceState ) >= ISERR_SUCCESS) then // 停止并卸载原来的服务 ServiceStopService ( szServiceName ); ServiceRemoveService ( szServiceName ); endif; ServiceAddService ( szServiceName, szServiceDisplayName, szServiceDescription, szServicePathFile, bStartService, szStartServiceArgs ); SdShowMsg(szMsg, FALSE); end;
  回到setup.rul脚本中,将下面相关行注释掉,阻止安装过程中出现SQL登录窗口,以便通过脚本程序控制SQL登录和执行SQL脚本,实现任意目录的安装。

view plaincopy to clipboardprint?

  1. Dlg_SQLServer:   
  2. //nResult = OnSQLServerInitialize( nResult );
  3. if( nResult = BACK ) goto Dlg_SdFeatureTree; 

Dlg_SQLServer: //nResult = OnSQLServerInitialize( nResult ); if( nResult = BACK ) goto Dlg_SdFeatureTree;
  编译并重建安装工程,至此,可以在任意目录下安装的MSDE2000最小版本(仅数据库核心)成功建立,网上的一些绿色MSDE2000版本只需用于应用程序的测试,与应用程序一起集成分发,客户端的安全性可以得到有效保证(微软原始文件),安装包也显得非常专业,当然,实现安装时实例名及sa密码的更改就更理想了,这个问题留待下一步解决。
  参考文档:
http://support.microsoft.com/kb/224071
http://support.microsoft.com/kb/288809/zh-cn