您的位置:首页 > 其它

InstallShield安装新版本时卸载老版本

2012-03-11 10:47 555 查看
InstallShield安装新的打包程序时,默认会提示下面的对话框,大意是说已经安装了产品的另一个版本,要用户手动去卸载老版本,不是很友好。



下面是对InstallShield在安装新版本时自动卸载老版本的一些尝试,主要是Install Script程序的编写。

1.首先要将Installation Designer–》Upgrades–》Prepare Setup For Upgrade Scenarios–》Upgrade Windows Installer Setup–》common下的Small/Minor Upgrade Settings选择为Don’t prompt user,just install the upgrade。这样不会出现上面的提示框,继续下面的卸载和安装。

2.下一步是要对OnResumeUI事件进行响应,主要是OnResumeUIBefore和OnResumeUIAfter。

3.在OnResumeUIBefore中完成老版本的卸载,脚本如下:

//---------------------------------------------------------------------------

// OnResumeUIBefore

//

// The OnResumeUIBefore event is called when end user runs installation that

// is performing a resumed install. Usually this happens by specifying

// a property like REINSTALL or ADDLOCAL at the command line when the

// product is already installed. After this function returns,

// ComponentTransferData is called to perform file transfer.

//---------------------------------------------------------------------------

function OnResumeUIBefore()

string szfilename, szmsg1, szmsg2;

int nresult;

STRING szDir, szIcon;

begin



nresult = MessageBox("新版本安装之前将卸载旧版本,是否继续?", MB_YESNO);

if(nresult = IDNO)then

abort;

endif;

szfilename = UNINSTALL_STRING +" /UNINSTALL /hide_progress";

nresult = StrFind(szfilename,".exe");

if nresult >=0 then

StrSub(szmsg1,szfilename,0,nresult + 4);

StrSub(szmsg2,szfilename,nresult + 4,200);

LongPathToQuote(szmsg1, FALSE );

LongPathToQuote(szmsg2, FALSE );

//szfilename = "\"" + szmsg1 + "\"" +szmsg2;

endif;

if(LaunchAppAndWait(szmsg1, szmsg2, LAAW_OPTION_WAIT_INCL_CHILD | LAAW_OPTION_WAIT) < 0 )then

MessageBox("旧版本卸载失败", MB_OK);

abort;

else

WaitForApplication(LAAW_PROCESS_INFORMATION.hProcess, LAAW_PROCESS_INFORMATION.dwProcessId, INFINITE, LAAW_OPTION_WAIT_INCL_CHILD | LAAW_OPTION_WAIT);

endif;

szIcon = DesktopFolder;

DeleteFolderIcon(szIcon, "AliProbe");

szDir
= INSTALLDIR + "AliProbe V1.1";

DeleteDir(szDir, ALLCONTENTS);

end;


需要注意的地方是,在调用LaunchAppAndWait方法等待老版本卸载完成的时候,一定要加上LAAW_OPTION_WAIT_INCL_CHILD ,主要是因为卸载的过程是Windows Install启动卸载程序,所以一定要等待Windows Install的子进程结束,否则将不能等待。

4.在OnResumeUIAfter中完成新版本的安装,脚本如下:

//---------------------------------------------------------------------------

// OnResumeUIAfter

//

// The OnResumeUIBefore event is called when end user runs installation that is

// performing a resumed install. Usually this happens by specifying a property

// like REINSTALL or ADDLOCAL at the command line when the product is already

// installed. In the handler, installation usually displays UI that will

// inform end user that Reinstallation has been completed successfully.

//---------------------------------------------------------------------------

function OnResumeUIAfter()

STRING noUse;

NUMBER szProcessId;

NUMBER nvProcessHandle; // Handle to a process

NUMBER nvModuleHandle; // Handle to a process module

STRING szModuleName; // Module filename

NUMBER nvBytesRequired;



begin

szProcessId
= GetCurrentProcessId();

if szProcessId != 0 then

if ProcessRunning(noUse, szProcessId, szModuleName) = TRUE then

LaunchApp(szModuleName, "/hide_progress");

else

MessageBox("自动安装新版本遇到问题,请再次运行安装文件完成安装。", MB_OK);

endif;

else

MessageBox("自动安装新版本遇到问题,请再次运行安装文件完成安装。", MB_OK);

endif;

end;


这里是通过GetCurrentProcessId得到当前进程的Id,并调用ProcessRunning获取当前进程模块的完整路径。

5.ProcessRunning的脚本如下:

//////////////////////////////////////////////////////////////////////////////

//

// Function: _Process_Running

//

// Description: Determines if the specified process is running in memory.

//

// Parameters: szAppName - Name of the application to check.

// nvFindProcessId - ID of the process to find.

// szFindModName - Name of the Module of the found process

//

// Returns: TRUE - The process is running.

// FALSE - The process is not running.

//

//////////////////////////////////////////////////////////////////////////////



function BOOL ProcessRunning(szAppName, nvFindProcessId, szFindModName)

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("ERROR: Could not load [" + 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.

//Add by QianShi at 2010.6.23

//Get module name by process id.

if nvProcessIDs(nvIndex) = nvFindProcessId then

szFindModName = svModuleName;

bvRunning = TRUE;

goto ProcessRunningEnd;

endif;

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("ERROR: Could not unload [" + WINSYSDIR ^ PSAPI_FILE +

"].", SEVERE);

return FALSE;

endif;

return
bvRunning;

end;


程序的功能主要是枚举当前的进程Id,并通过Id匹配来得到Id对应的Module name,本函数同样可以判断某个name的进程是否正在运行。

以上就是本人对用IS脚本完成安装新版本前卸载老版本的方法, 如果大家有其他好的方法,请多多指教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: