原帖地址: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?
- 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
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?
- 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
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?
- //////////////////////////////////////////////////////////////////////////////
- //
- // 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;
////////////////////////////////////////////////////////////////////////////// // // 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?
- #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;
#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?
- Dlg_SQLServer:
- //nResult = OnSQLServerInitialize( nResult );
- 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