InstallShield2008如何实现安装完重启并且将服务安装

1。我生成了一个服务,可以用安装部署来安装成功,我选择的是自动启动模式,但是安装完后必须重启后才能启动服务或者安装完后手动启动,如何设置使之安装完后可以直接启动服务啊?

3。安装程序结束后,我想最后出线一个完成的按钮,而不是默认的关闭按钮,而且可以加一个复选框,默认的是重启,也就是点“完成”后如果复选按钮选了就重启,不选就不重启,这个如何加?当然还有复选按钮对应的操作如何加?(就像咱普通的一些安装程序,最后有个完成,而且有复选框,选择readtext复选的话,点击完成后就弹出来一个txt的使用说明文件)

但是第1项呢,如何安装我的一个服务啊,还有第3项,如何提示重启,并且我想在安装完成后执行一个小程序?


海洋女神 发表于 2010-11-12 11:40

第一个问题. ServiceStartService函数可以启动服务,建议写在OnEnd里
第三个问题,参阅http://www.cnblogs.com/Cindy_weiwei/archive/2009/05/19/1460238.html中第七小节和第八小节

第三个问题中如果你只是想重启电脑,建议用radiobutton而不是checkbox,直接把SdFinish改成SdFinishReboot就可以了。第七小节你看完就知道在哪里改了。


http://www.appinstall.cn/archiver/?tid-785.html


一个完整的Installshield安装程序实例—艾泽拉斯之海洋女神出品(四) --高级设置二  节选


7. 在安装结束时,允许用户选择是否显示桌面快捷方式


有时候我们会看到别的安装程序在安装过程中允许用户选择是否要在桌面上显示快捷方式,一开始因为我们公司的分布式系统的组件太多了,不想显示在桌面上,而且觉得和在开始菜单中显示快捷方式的原理是一样的,因此也就轻轻带过;后来经理抱怨说没有桌面快捷方式,总是要去开始菜单找,觉得麻烦,而且客户是使用专用计算机运行我们的程序,也就是桌面上会很干净,希望我能够做这个功能出来。我试了一下,发现和在开始菜单中显示快捷方式还是有一点不同的,也是值得写出来的,至少可以让读者少走一些弯路。


1. 首先要显示一个允许用户选择是否显示桌面快捷方式的界面,这个界面上要有一个checkbox(钩选框),当钩选了以后,安装程序就要在安装时为用户显示桌面快捷方式。


这段代码的位置是在After Move Data | OnFirstUIAfter()的函数里实现的,也就是和“显示readme文件”的功能放在一起。


把从Disable(STATUSEX);起到SdFinishEx这行的代码,全部替换成如下代码:


Disable(STATUSEX);


ShowObjWizardPages(NEXT);


bOpt1 = TRUE;


bOpt2 = TRUE;


szMsg1 = SdLoadString(IFX_SDFINISH_MSG1);


szTitle="";


szMsg1="";


szMsg2="";


szOption1="Show Readme";


szOption2="Create Shortcut on Desktop?";


SdFinishEx(szTitle, szMsg1, szMsg2, szOption1, szOption2, bOpt1, bOpt2);


2. 代码解释


与上面的“显示readme文件”中的代码相比,只动了一个地方,即szOption2="Create Shortcut on Desktop?";


这个是一个Checkbox,如果值设置为空则不显示,如果赋值则显示一个Checkbox并且在这个Checkbox旁边显示这个所赋的简短值。


这里我们需要它显示出来,这样在界面上用户就会看到一个钩选框询问是否要显示桌面快捷方式。


3. 接下来我们要对用户所做的选择做一些判断,并且显示桌面快捷方式,在这段代码后面加上


if(bOpt2=TRUE) then


if (FeatureIsItemSelected(MEDIA, szFeatureName1)=1) then


szDocFile = TARGETDIR^"Server\\server.bat";


LongPathToQuote(szDocFile, TRUE );


AddFolderIcon(FOLDER_DESKTOP, "Server" , szDocFile, TARGETDIR^"Server" , TARGETDIR^"Server\\icons\\appClient.ico" , 0 ,"" , REPLACE );


endif;


4. 代码解释


因为上面对这些函数的每个参数都有详细解释了,所以这里就不做一一解释了,只对要注意的地方做说明。


这里,一开始,笔者对第四个参数仍然传的是空字符串,但是创建的快捷方式总是不能运行,对比属性面板才发现,桌面快捷方式的“起始位置”的值居然是空的,看来Help解释的“当传空值的时候,默认为快捷方式所指的应用程序所在的目录”并未生效,只好老老实实地把运行目录的值手动地传进去。


读者可能注意到在AddFolderIcon函数里的第三个参数被做了一些预处理,这个处理也是折腾了几次才搞出来的,不同的操作系统默认路径也是有是否带引号的差别的,这里需要显式地指定一下,以免在不同操作系统上运行时引起不同的结果。


8. 在安装结束后,启动指定的程序


在全部安装完毕后,启动指定的程序,向Windows安装一个服务。或者也可使用于安装结束后的程序的自启动。


1. 这部分很明显是要在安装全部结束后进行的,因此放在After Move Data | OnEnd里


2. 把OnEnd()的代码替换如下


function OnEnd()


STRING szFeatureName;


STRING serviceTarget;


STRING szDocFile;


begin


/*


//这个服务所需的文件只有在钩选了某feature时候才会被拷贝,并且也只有在用户钩选安装了此feature时候才会在安装结束时安装此服务,因此首要判断是否选择了此feature,然后寻找到该执行文件,并且进行安装


*/


szFeatureName="Watch_Portion";


serviceTarget=TARGETDIR^"watch.exe";


if (FeatureIsItemSelected(MEDIA, szFeatureName)=1) then


if(FindFile(TARGETDIR, " watch.exe ", szDocFile)=0) then


if (LaunchApp (serviceTarget, "") < 0) then


MessageBox ("Unable to launch "+serviceTarget+".", SEVERE);


endif;


endif;


endif;


end;


3. 代码解释


***************************************************************************************


if (FeatureIsItemSelected(MEDIA, szFeatureName)=1) then


endif;


首先判断这个feature是否被用户选择安装。因为在这个应用程序里这个服务只与此feature相关,因此要做一下判断,如果用户没有安装这个feature,就不需要启动这个服务了。


当用户选择了这个feature时,返回值为0


***************************************************************************************


if(FindFile(TARGETDIR, " watch.exe ", szDocFile)=0) then


endif;


这个是判断一下文件是否被正确地拷贝过去了,这个文件应该位于安装目录下,名为watch.exe。当该文件存在时,返回值为0


***************************************************************************************


if (LaunchApp (serviceTarget, "") < 0) then


endif;


启动该服务;如果启动失败,则返回小于0的值。


这里LaunchApp的用法和上面第6段的用法略有不同。这个函数的本意是启动第一个参数指定的运行程序来打开第二个参数指定的文件。这里第二个参数指定为空,因为没有要打开的文件;第一个参数指向我们需要启动的可执行程序即可。


***************************************************************************************


MessageBox ("Unable to launch "+serviceTarget+".", SEVERE);


如果上一步中判断到程序未能正确启动,则弹出一个错误提示框体现用户。


小结:这段代码的用法非常简单,但是如果用在适当的安装程序里会非常重要;笔者的安装程序,在一开始的时候需要用户安装完毕后手动地去安装目录里找到这个服务并且启动,使人感觉非常不友好;现在在安装完毕后做到了静默启动,用户无需做任何事情。而且这个服务需要JDK的支持,配合上述第2段中判断是否安装了JDK这个应用,就不会出现安装了此服务但是无法运行的局面。


9. 安装结束后,为JDK设置一个环境变量


之前提到了,要在安装本系统时判断是否安装了JDK,在最初笔者所做的安装盘中,还要让用户手动地去为JDK设置环境变量JAVA_HOME,设置环境变量对于外行来说简直就是天方夜谭,在JAVA论坛新手区最常见就是求助设置环境变量的问题了,因此,这个功能最好还是由安装程序代劳为妙。


1. 这段代码在After Move Data | OnFirstUIAfter()里


//write the environment variable


szKey = "SOFTWARE\\JavaSoft\\Java Development Kit\\1.6.0_04";


RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);


if (RegDBKeyExist(szKey)=1) then//如果该注册表值存在


if(RegDBGetKeyValueEx(szKey,"JavaHome",nvType,svValue,nvSize)=0) then//获取注册表值成功


szKey = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";


if(RegDBSetKeyValueEx(szKey, "JAVA_HOME", REGDB_STRING, svValue, -1)<0) then


MessageBox ("Javahome create failed, please set it manually!", SEVERE);


endif;


endif;


endif;


2. 代码解释


****************************************************************************


RegDBKeyExist(szKey)


判断JDK1.6.0_04的注册表值是否存在;要判断JDK1.6.0_04是否被安装,只有通过注册表来判断啦,同理可得,要是自己开发的一套系统中有多个安装程序,而且相互关联,就得朝注册表里写入值了。


如果返回值为1,则说明存在该键值;


如果返回值小于0,则说明该键值不存在。


****************************************************************************


RegDBGetKeyValueEx(szKey,"JavaHome",nvType,svValue,nvSize)


因为设置JAVA_HOME环境变量需要JDK的安装位置,所以要根据注册表来寻找到这个安装位置,而幸运的是,该键值下的JavaHome键名所对应的值就是JDK的安装位置。


Help里对该函数的解释如下:


RegDBGetKeyValueEx ( szKey, szName, nvType, svValue, nvSize );


参数一:szKey, 要查找的注册表的键,这里我们查找SOFTWARE\\JavaSoft\\Java Development Kit\\1.6.0_04


参数二:szName,一些注册表键下面会有一些键名,如果你去看一下我们查找的键,会发现该键下存在多个键名,这里我们只要查找JavaHome键名对应的值,因此,指定szName为JavaHome


参数三:nvType,返回该键名对应的值的类型,比如字符型,数字型;当时笔者还犯了一个错误,以为这个参数是需要笔者指定类型的,因此写了一个REGDB_STRING,结果编译出错,搞了半天发现这个参数是个返回值,汗一个。


参数四:svValue,返回该键名对应的值


参数五:nvSize,返回该键名对应的值的字节数


****************************************************************************


szKey = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";


RegDBSetKeyValueEx(szKey, "JAVA_HOME", REGDB_STRING, svValue, -1)


如果搜索注册表发现JDK已经安装了,就去读一下注册表的键值,并且设置我们所需要的环境变量,这两句话就是用来设置环境变量的。


环境变量也是利用注册表键值设置函数RegDBSetKeyValueEx来实现的,这个键是一个特殊的位置,一定是"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",我们对该函数进行进行详细说明。


RegDBSetKeyValueEx ( szKey, szName, nType, szValue, nSize );


函数作用:设置注册表键值


参数一:szKey注册表里的键,这里,我们需要设置环境变量的值,因此这里固定传值为"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"


参数二:szName,键名,这里我们需要设置的是名为JAVA_HOME的环境变量


参数三:nType,被设置的键的类型,这里是字符串型,并且不带%PATH%之类的符号,也不转行


参数四:szValue,就是键值了,这里我们已经从上面得到了JDK的安装路径,就把安装路径传进去


参数五:nSize,help里说明如果键类型为REGDB_STRING, REGDB_STRING_EXPAND, 或者 REGDB_NUMBER时,都可以设置该值为-1,installshield会自动为我们计算正确的长度,而当键类型为REGDB_BINARY 和REGDB_STRING_MULTI时,就必须传该键值的实际大小进去。


小结:Installshield默认键值位置是在HKEY_CLASSES_ROOT下的,因此在这里,我们需要在进行搜索键值和设置键值的操作之前使用RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);这句话来设置一下默认的根键值为HKEY_LOCAL_MACHINE;另,在网上看了一个帖子,当时匆匆看了一下,说是设置的键值会在反安装时候卸载掉,我倒是没有在自己的安装程序里发现这个问题,不过可以研究一下;作者说当时为了解决这个问题,是在代码头加上DISABLE(LOGGING);代码尾加上ENABLE(LOGGING)来实现的,虽然我没有碰到这个问题,但是还是很感谢这位作者,因为当时他也说了,根本找不到资料,自己啃了天书般的HELP来解决,而自己一旦解决了问题,就分享出来,以便于大家少走弯路。


10. 完美卸载


在第一部分的第9点我们提到过InstallScript工程里自带的Uninstall快捷方式的缺陷,这里我们将会创建一个可以实现全部卸载的卸载方式,这个卸载方式会以快捷方式出现在开始菜单下,利用安装程序本身的反安装功能来实现


3. 这段代码在After Move Data | OnFirstUIAfter()里,和其他创建快捷方式的代码放一起


function OnFirstUIAfter()


STRING szfilename,szFolder ,szmsg1,szmsg2;


NUMBER nresult;


begin


//创建删除快捷方式


szfilename = UNINSTALL_STRING +" /UNINSTALL";


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;


AddFolderIcon(FOLDER_PROGRAMS^"Test","Uninstall",szfilename,WINDIR,"",0,"",REPLACE);


End;


4. 代码解释


****************************************************************************


szfilename = UNINSTALL_STRING +" /UNINSTALL";


参数一:UNINSTALL_STRING这个静态变量指向的就是我们的安装程序,也就是setup.exe,不过指向的位置不是我们的源盘里的setup.exe,而是C:\Program Files\InstallShield Installation Information\{0D9DF66A-44E5-4754-A522-2AD6C9D5CDBE}\setup.exe;Installshield创建的安装文件在安装时总会在这个文件夹里创建对应信息,一长串数字型序列码就是安装程序的Product ID。利用这个setup.exe就可以进行反安装


参数二:/UNINSTALL,告诉程序启动这个setup.exe时为非安装状态,即修复、重新安装和卸载状态。


因此,这个字符串的值应该是这种形式:


"C:\Program Files\InstallShield Installation Information\{0D9DF66A-44E5-4754-A522-2AD6C9D5CDBE}\setup.exe" -runfromtemp -l0x0409 /UNINSTALL


****************************************************************************


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


寻找到“.exe”这个字符串在szfilename这个字符串中的位置。


Help里对这个函数的描述如下:


StrFind (szString, szFindMe);
参数一:szString,被查找的源字符串


参数二:szFindMe,要查找的字符串


返回值为要查找的字符串在源字符串中的位置,如果返回值小于0,则说明源字符串中找不到要查找的字符串


****************************************************************************


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


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


如果要查找的字符串存在,那么源字符串就是正确的;这两句语句就对源字符串进行截断,得到想要的子串。


szmsg1应该为C:\Program Files\InstallShield Installation Information\{0D9DF66A-44E5-4754-A522-2AD6C9D5CDBE}\setup.exe


而szmsg2应该为 -runfromtemp -l0x0409 /UNINSTALL


Helpl里的解释如下:
StrSub ( svSubStr, szString, nStart, nLength ); 
参数一:svSubStr返回的结果字符串
参数二:szfilename源字符串
参数三:开始截断的位置。如果指定的位置大于整个被解析的字符串长度,则返回一个空字串。
参数四:结束截断的位置。如果指定的位置大于整个被解析的字符串长度,则默认为结束截断的位置是字符串的结尾处。
****************************************************************************


LongPathToQuote(szmsg1, FALSE );


LongPathToQuote(szmsg2, FALSE );


这两句的作用是对上面解析出的两个子串脱去括号。原本笔者参考的例子里没有这两句,在自己计算机上运行正常,但是换了一台计算机后,创建出的卸载快捷方式无效,查看快捷方式的指向发现和原来计算机的指向略有差别,查阅了一些资料得知Windows下的长文件名就有这个缺陷,每个操作系统解析出来的可能会有所不同,主要是引号的麻烦。在笔者自己的计算机上获取的长文件名是不带引号的,因此,解析正确;而测试的那台计算机上获取的文件名却是带引号的,这就造成了解析后拼凑的字符串的差别。这里就要显式地为解析出来的子串脱一下引号。


****************************************************************************


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


拼凑出正确的可执行文件的长文件名,带路径,包含扩展名


****************************************************************************


AddFolderIcon(FOLDER_PROGRAMS^"Test","Uninstall",szfilename,WINDIR,"",0,"",REPLACE);


添加一个快捷方式到开始 | 所有程序 | Test下;照抄即可。


小结:可能读者会比较奇怪这一段代码的写法,因为中间那段if endif;代码看上去简直就是多此一举。在Installshield7之前,一直是这样写的:


szfilename = UNINSTALL_STRING +" /UNINSTALL";


AddFolderIcon(FOLDER_PROGRAMS^"Test","Uninstall",szfilename,WINDIR,"",0,"",REPLACE);


从Installshield8开始,长文件名一直有引号封闭不正确的问题,因此if endif;代码完全是为了解决这个问题而存在的,而上面提到的两个脱去引号的语句,是笔者在前人基础上修改加上的,因为发现解析出来的字串要是不脱一下括号还是有问题。


这个快捷方式运行的时候,出现界面和在安装完毕后再次运行安装程序出现的界面相同。选择Remove即可进行卸载。






这个卸载不会把程序运行时产生的文件卸载掉,比如日志文件、配置信息文件等;会把安装目录中所有从安装程序中安装的文件都卸载掉,包括安装时从外部拷贝的文件。利用Project Assistant创建的卸载快捷方式则无法卸载掉安装时从外部拷贝的文件。


11. 完美卸载之卸载时触发命令(卸载Windows服务)


在做完这个安装程序后,以为可以结束了,没想到经理又提出了一个新的要求,因为之前的安装里(参阅第二部分的第8小节),在安装完毕后,启动了一个指定程序,这个指定程序干的事情就是向Windows写了一个服务进去(有兴趣的同学可以去看看Java Service相关资料,是一个把Java程序注册为Windows服务的一个工具或者说是组件更合适些);所以,这里希望能够在卸载的时候能够把这个服务给卸载掉。


首先我们介绍一下两条Windows cmd命令:


1) SC stop XXX


这条命令用于停止某个名叫XXX的正在运行的Windows服务


2) SC delete XXX


这条命令用于删除某个名叫XXX的Windows服务


一开始我的思路是这样的,获取安装程序的卸载状态,然后调用这两条命令来删除服务;没想到这个“获取安装程序的卸载状态”让我浪费了整整一个下午的时间,只知道MAINTENANCE是程序的反安装状态,而这个反安装状态是有可能包括“重装”、“修复”和“卸载状态”的,当然我可以让反安装界面只能处于卸载状态,只要把前面创建卸载快捷方式中的szfilename = UNINSTALL_STRING +" /UNINSTALL"; 这句话改成szfilename = UNINSTALL_STRING +" /REMOVEONLY"; 就可以了;但是试验出来是不等我确认删除,这个服务就卸载掉了,原因是这个界面一出来就是MAINTENANCE状态,而程序捕获了这个状态后,是不管我是否按下了确认按钮就会去做这个操作了。


后来想在Onbegin里添加一个SdWelcomeMaint函数的判断,结果是判断倒是成功的,但是多了另一个重复界面。


看来这个思路可能是有问题的,然后满地google之,还是吞硬币的小猪的一篇文章给了启发,原文地址找不到了,只找到了这篇http://school.ogdev.net/ArticleShow.asp?id=1699&categoryid=7,这里面其实是谈反安装时候不执行OnMaintUIBefore函数的问题,我想既然这个函数是反安装时候“应该执行的”,那么就看看这个函数吧。


于是 打开Before Move Data | OnMainUIBefore






打开一看,大喜过望,这个函数里明明白白地显示了反安装时候的所有界面。


于是顺着向下看,找到Dlg_SdFeatureTree。






这里红色圈出来的一行代码明确地告诉我们:如果为反安装状态,那么卸载所有组件!OK,代码只要添在这里就可以了。






这里就运用了一个函数LaunchAppAndWait来达到目的。其实一开始我还在想是不是要写批处理文件来执行呢,结果是不需要,直接写在这个函数里就可以了。


LaunchAppAndWait ( szProgram, szCmdLine, nOptions );


参数一:szProgram,要运行的程序。在Help里有这样一句解释:想在命令行里指定要运行的程序,那么可以对这个参数传空值


参数二: szCmdLine,命令行参数;很奇妙的参数,这里我们就可以写入我们想要的批处理语句了。


参数三:静态变量,操作类型,这里LAAW_OPTION_HIDDEN可以使批处理窗口隐藏掉,如果使用了LAAW_OPTION_WAIT,就会看到一个命令行窗口一闪而过,让人十分不爽。


于是,折腾了一下午的问题,就靠这短短的两分钟就解决了… 

http://www.cnblogs.com/Cindy_weiwei/archive/2009/05/19/1460238.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值