用InstallShield 2010做C#写的windows服务的安装包:http://www.nnllok.cn/Read.aspx?cid=8&id=526
2003年11月9日 星期日 02:32:06根据CSDN文集整理的《InstallShield内部库函数全集》在永硕E盘的“学习->Installshield”下有下载,是chm文件,带索引和全文检索
InstallShield InstallScript: Uninstallation:http://www.installsite.org/pages/en/isp_uninst.htm
这个页面里有Avoid Maintenance Mode in IS6,去掉重复执行setup.exe文件时显示的那个维护对话框,带修改、维护、卸载的那个
很多服务都带一个服务控制程序,可以对服务做各种设置和操作的,像停止服务、开始服务,或者设置服务运行需要用到的参数,在安装的时候,这个控制程序也要安装进去,卸载的时候,也要同时卸载
先讲安装
安装的时候好简单,就是再多加一个Components,右击Components,使用New Component菜单,再展开的Files里,添加控制程序文件就可以了
控制程序一般都要设置快捷方式,这里讲一下啰,进入Project Assistant标签,进入Application Shortcuts,在这里可以添加快捷方式:
1.Create an uninstallation shortcut,这个是添加一个卸载的快捷方式
2.Shortcuts,这个是添加指向应用程序的快捷方式
这些快捷方式添加完,也可以进入Installation Designer标签后,进入Components里,在对应Component下的Shortcuts里设置快捷方式在开始菜单里的文件夹名称
如果有多个快捷方式是放在不同的Component下的,在System Configuration -> Shortcuts里直接设置,会更方便
嗯,我用Project Assistant标签添加卸载的快捷方式,是因为不用手动设置卸载的各种属性。。。熟悉属性的话,可以直接在Component里设置的
安装好简单,没的好讲的,下面讲卸载
is里,卸载的时候,不会检测服务控制程序是不是正在运行,有时候,一个控制程序正在后台运行,用卸载的时候,可以不退出这个程序,就直接卸载掉的,这里我想不明白,为什么控制程序在运行的时候,在我的电脑里不可以手动删除控制程序文件,就是,卸载就可以把这个文件删除掉呢?文件被删除掉了,文件还在运行。。。我想是不是因为控制程序好小,运行的时候是在高速缓存里呢?就是,就算是在缓存里,文件还是被锁定的啊,我想不明白为什么卸载可以卸掉一个锁定的文件
就是,想不明白也要解决这个问题啊,对不对?
要解决这个问题,就要在卸载前判断控制程序是不是在运行,一个控制程序运行的时候,是在锁定状态的,所以可以借判断文件是不是在锁定状态来判断程序有没有在运行
要知道一个文件是不是锁定状态,就要知道这个文件的完整路径,安装的时候,一般是可以允许用户自定义安装路径的,所以安装程序是不知道控制程序的最终路径的
所以,要在安装时,先把安装路径写入注册表,再在卸载时,从注册表读取这个路径,再判断文件是不是在锁定状态
下面是操作步骤,全部都在Installation Designer下进行:
1.添加注册表项
进入System Configuration->Registry,如图设置注册表项

这里,我准备把我的安装路径写在这里:HKEY_LOCAL_MACHINE\SOFTWARE\RbTest,其中RbTest是我自己的程序注册项文件项
这里的操作有不明白的,可以看这里:http://www.nnllok.cn/myBlog/archives/2006/2757.html
2011-03-19 14:57记录:下面的第2步是2011-03-17用的方法,在6.02版,动态写入注册表项时,如果是要写入安装路径,可以用<TARGETDIR>,那天我测试过,不可以,这个字符串被直接写进注册表项了,所以我用了代码写
就是,现在知道,在2010版里,写注册表时,可以用[INSTALLDIR]写安装路径
还有就是,如果只需要写安装路径,可以直接勾选一个设置的,具体看最下面的图
2.动态写入注册项的键值
①编写函数
进入Behavior and Logic,点击InstallScript,在右侧,右击Files,选择New Script File,如图:

右击这个脚本,选择Edit Script,进入脚本编辑器后,添加以下函数:
2011-03-19 13:01记录:这个函数的缺点在没有判断是卸载还是安装,所以在写入注册表项时,是只要函数被执行了,就写,我在设置action的时候,设置成After WriteRegistryValues,所以修改了注册表项后,包括写入和删除,都会执行这个函数,所以会导致卸载程序时,注册表项会在删除后重新建立,导致留下注册表项删除
要判断是安装状态,使用:if !MAINTENANCE then
///////////////////////////////////////////////////////
///NNLL 20100317 1402 安装结束时把安装路径写入注册表///
///////////////////////////////////////////////////////
export prototype SetInstallDir(HWND);
function SetInstallDir(hMSI)
number nType,nSize;
string szKey,szNumName,szNumValue,szClass;
begin
//设置根是HKEY_LOCAL_MACHINE
RegDBSetDefaultRoot (HKEY_LOCAL_MACHINE);
//注册安装路径
szKey = "SOFTWARE\\RbTest\\";
szNumName = "installDir";
szNumValue = TARGETDIR;
nType = REGDB_STRING;
szNumValue = TARGETDIR;
nSize = -1;
if RegDBSetKeyValueEx(szKey, szNumName, nType, szNumValue, nSize) < 0 then
MessageBox("设置注册表项失败", WARNING);
endif;
end;
②添加函数调用
进入Behavior and Logic,点击Custom Actions and Sequences,在右侧右击Custom Actions,选择Custom Action Wizard,如图

进入Wizard后,第1步是Basic Information,这里只要在Name输入你的脚本描述就可以了,我输入的是“SetInstallPath”
第2步是Action Type,这里的Type,选择:Run InstallScript code
第3步是Action Parameters,这里的Source选择要调用的函数,我上面在脚本里添加的函数名是SetInstallDir,所以我从下拉菜单里选择的是“SetInstallDir”
第4-5步选择默认
第6步是Insert into Sequence,这里是设置你的action要在什么时候调用的,在Install Exec Sequence里选择:After WriteRegistryValues
后面的全部默认就可以了
这样子的设置是要在写入了注册表项后执行这个action,执行时调用SetInstallDir函数,这个函数呢,会写入一个注册表键值记录安装路径
3.在卸载时通过判断文件有没有锁定,判断控制程序是不是正在运行
①编写函数,在上面的脚本文件里,再加入一个函数:
2011-03-19 15:05记录:以下函数是在2011-03-16写的,在2011-03-17修改完毕,用的方法是读取自定义注册表项的方法,缺点在没有判断当前是在安装还是在卸载,要做这个判断用:if MAINTENANCE then,具体看最后
/////////////////////////////////////////////////////////
///NNLL 20110316 1540 卸载时先检查控制器程序有没有运行///
/////////////////////////////////////////////////////////
export prototype CheckIfExeRuning(HWND);
function CheckIfExeRuning(hMSI)
string szKey, szName, svValue, szReferenceFile;
number nType, nSize, nContinue;
begin
RegDBSetDefaultRoot (HKEY_LOCAL_MACHINE);
szKey = "SOFTWARE\\RbTest\\";
szName = "installDir";
nType = REGDB_STRING;
nSize = -1;
if RegDBGetKeyValueEx (szKey, szName, nType, svValue, nSize) = 0 then
//从注册表读取程序安装路径
szReferenceFile = svValue + "P___Control.exe";
//检查控制程序是不是被锁定的,如果程序正在运行,是锁定状态的
while (Is( FILE_LOCKED, szReferenceFile ))
if AskYesNo("服务控制程序P___Control.exe正在运行,要继续卸载请先退出该程序后单击“YES”。\n要退出卸载请单击“NO”", YES) = 0 then
abort;
endif;
endwhile;
else
MessageBox("获取程序安装路径失败,请自行确认服务控制程序P___Control.exe是否已退出", WARNING);
endif;
end;
②添加函数调用,操作和上面的相同,就是到第6步Insert into Sequence时,Install Exec Sequence要选择:After StopServices
因为前面讲安装服务的时候,已经设置过is在卸载时自动暂停服务了,所以这里可以在暂停服务后做判断
通过上面的三个步骤后,卸载时控制程序如果正在运行,就会弹出一个提示,要求用户退出程序后再继续了,安装和卸载到这里全部搞完
----------------------------------------------------
以下是2011-03-19记录:
1.写注册表
①自定义注册表路径,在System Configuration -> Registry下如图操作,[INSTALLDIR]可以动态写入安装路径:

②如果只需要写入安装路径,不需要写入别的信息的,可以不用自定义注册表路径的,在Organization -> Components里如下图设置:

勾选上这个后,is会在HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\FileName.exe下面写入FileName.exe的安装路径
这个方法是星星告诉我的,我差一点点和星星吵架了。。。因为如果我没有发现我写注册表的方法没有判断安装还是卸载,会导致卸载完也会重复写入注册项,如果我没有为了解决这个问题,从Shortcuts的设置里想到[INSTALLDIR],没有把这个bug告诉星星,没有告诉星星我的解决办法,星星就不会告诉我他用的是这个办法。。。我写这个is的东西,是为了星星写的,他看完,知道更简单的办法,没有告诉我,星星说以为我什么都知道,我怎么可能什么都知道呢?我好多都不懂,我从来不知道注册表里app path里是记录安装路径的,如果我知道这个注册表,我会想到is肯定会有这样子的快捷设置,我会找,就是,我不知道。。。就是,妈妈说这个是我的计算机基础的问题,不是星星的问题,因为星星不知道我连最基本的东西都不懂。。。
所以。。。好久好久以前,小狮说过的话,基础是最重要的
做了这个设置后,System Configuration -> Registry下会自动生成下图注册表项:

2.在卸载时检测控制程序是否正在运行,对应上面的设置,函数最终修改如下:
/////////////////////////////////////////////////////////
///NNLL 20110317 1445 卸载时先检查控制器程序有没有运行///
/////////////////////////////////////////////////////////
export prototype CheckIfExeRuning(HWND);
function CheckIfExeRuning(hMSI)
string szKey, szName, svValue, szReferenceFile;
number nType, nSize;
begin
if MAINTENANCE then
RegDBSetDefaultRoot (HKEY_LOCAL_MACHINE);
szKey = "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\P___Control.exe";
szName = "";
nType = REGDB_STRING;
nSize = -1;
if RegDBGetKeyValueEx (szKey, szName, nType, svValue, nSize) = 0 then
//从注册表读取程序安装路径
szReferenceFile = svValue;
//检查控制程序是不是被锁定的,如果程序正在运行,是锁定状态的
while (Is( FILE_LOCKED, szReferenceFile ))
if AskYesNo("服务控制程序P___Control.exe正在运行,要继续卸载请先退出该程序后单击“YES”。\n要退出卸载请单击“NO”", YES) = 0 then
abort;
endif;
endwhile;
else
MessageBox("获取程序安装路径失败,请自行确认服务控制程序P___Control.exe是否已退出", WARNING);
endif;
endif;
end;