一、主要思想是:
1、在初始化OnSetTARGETDIR函数中,if( MAINTENANCE ) then的条件中调用卸载函数(UninstallOldVersion);
2、在卸载函数中需要判断是否装有旧版本,给出提示框,访问用户是否要卸载;
3、卸载函数主要是通过GUID找到对应的程序安装路径、InstallShield卸载文件夹路径、将这些文件夹删除,然后删除快捷方式,再删除对应的注册表;
4、删除完成后,通过进程ID找到对应安装EXE的全路径,运行这个EXE程序,然后退出当前EXE程序。
注:GUID一定要是固定的。
二、相关卸载函数
1、函数声明:
prototype NUMBER KillProcess(string);
prototype BOOL GetProcessRunning(string, int, BYREF string);
prototype UninstallOldVersion();
prototype DeleteUninstallShortcut();
prototype Shell32.SHChangeNotify(LONG, LONG, POINTER, POINTER);
prototype Kernel32.GetCurrentProcessId();
2、函数定义:
function DeleteUninstallShortcut()
string strCmdLine, strProductFolder, strIconPath, strItemName,svPath;
begin
strProductFolder = "产品名称";
DeleteFolderIcon(FOLDER_PROGRAMS ^ strProductFolder,"产品名称");
DeleteFolderIcon(FOLDER_PROGRAMS ^ strProductFolder,"卸载产品名称");
DeleteFolderIcon(FOLDER_DESKTOP,"产品名称");
DeleteProgramFolder(FOLDER_PROGRAMS ^ strProductFolder);
end;
function UninstallOldVersion()
string szPath,UninstallString;
string szNumName,szNumValue;
number nType,nSize,nIgnore,nResult;
string szmsg1;
int nIndex;
string oldGuid;
string szTARGETDIR;
STRING noUse;
NUMBER szProcessId;
STRING szModuleName; // Module filename
begin
oldGuid = "{1F1C2DFC-2D24-3E06-BCB8-725134ADF989}";
szPath=WINDIR+"Installer\\"+oldGuid;
RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
UninstallString="\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"+oldGuid;
nType=REGDB_STRING;
szNumName="UninstallString";
nResult = VerProductCompareVersions();
RegDBGetKeyValueEx(UninstallString,szNumName,nType,szNumValue,nSize); //获取卸载脚本
if(RegDBKeyExist(UninstallString)>0 && nResult != VERSION_COMPARE_RESULT_SAME) then
if(AskYesNo("检测到旧版本存在,是否卸载?",NO)=YES) then
if ProcessRunning("Onekeyrom") then
MessageBox("程序正在运行中,请先关闭程序.", INFORMATION);
abort;
endif;
SdShowMsg("正在卸载旧版本, 请稍等...",TRUE);
Delay(1);
LaunchAppAndWait(szNumValue, " /S", LAAW_OPTION_WAIT);
szNumName = "InstallLocation";
nSize = 0;
RegDBGetKeyValueEx(UninstallString,szNumName,nType,szmsg1,nSize); //获取卸载脚本
KillProcess("aaa");
if (nSize > 0) then;
DeleteDir(szmsg1, ALLCONTENTS);
endif;
nIndex = StrFind(szNumValue,"}\\");
if nIndex >=0 then
StrSub(szmsg1,szNumValue,0,nIndex + 2);
LongPathToQuote(szmsg1, FALSE );
DeleteDir (szmsg1, ALLCONTENTS);
endif;
DeleteUninstallShortcut();
RegDBDeleteKey(UninstallString);
RegDBDeleteKey("\\SOFTWARE\\公司名称"); // 主要是看InstallShield设置注册表的路径
FeatureRemoveAllInMediaAndLog();
//刷新注册表
LaunchAppAndWait ( "","cmd /c gpupdate /force /wait:0 ",LAAW_OPTION_WAIT|LAAW_OPTION_HIDDEN);
SdShowMsg("", FALSE);
SdShowMsg("卸载旧版本成功",TRUE);
Delay(2);
SdShowMsg("", FALSE);
LaunchAppAndWait(WINSYSDIR^"cmd.exe", "/c rd /s/q \""+szPath+"\"", LAAW_OPTION_WAIT | LAAW_OPTION_HIDDEN);
szProcessId = GetCurrentProcessId();
if szProcessId != 0 then
if GetProcessRunning(noUse, szProcessId, szModuleName) = TRUE then
LaunchApp(szModuleName, "");
abort;
else
MessageBox("安装新版本遇到问题,请再次运行安装文件完成安装。", MB_OK);
endif;
else
MessageBox("安装新版本遇到问题,请再次运行安装文件完成安装。", MB_OK);
endif;
else
abort;
endif;
endif;
end;
function BOOL GetProcessRunning(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;
function NUMBER KillProcess(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
STRING szCmdLine, szTemp;
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 -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("ERROR: Could not unload [" + WINSYSDIR ^ PSAPI_FILE +
"].", SEVERE);
return -1;
endif;
return nvReturn;
end;