szSrcFile3 = \ //拷贝的目的地,目标文件夹
szTarFolder3 = TARGETDIR^\
szTarFolder4 = TARGETDIR^\文档的存放路径,不带文件名 2. 仍然在begin和end之间的函数体内把下面的代码拷贝进去即可
if (FeatureIsItemSelected(MEDIA, szFeatureName6)=1) then //如果选择了此feature if(CopyFile(SRCDISK^szSrcFile3, szTarFolder3)=0) then //那么把要拷贝的文件拷贝过去
nResult = FindAllFiles(TARGETDIR^\对拷贝过去的文件进行查找,该函数会在第一个符合条件//的文件处停止 while (nResult = 0)
LongPathToQuote(szDocFile, TRUE );
ParsePath (szDocFileName, szDocFile, FILENAME_ONLY);//对查找到的文件获取文件名 AddFolderIcon(FOLDER_PROGRAMS^\TARGETDIR^\为该文件创建快捷方式,快捷方式的显示名就是刚才获取的文件名
nResult = FindAllFiles(TARGETDIR^\从上一个查找的位置继续向下查找,进行循环 endwhile; endif; endif;
3. 代码解释
*************************************************************************************** if (FeatureIsItemSelected(MEDIA, szFeatureName6)=1) then endif;
如果用户选择了文档feature,则进行一些相应操作
*************************************************************************************** if(CopyFile(SRCDISK^szSrcFile3, szTarFolder3)=0) then endif;
这里执行了两步操作:
第一步,从源盘的Docs文件夹下把所有文件都拷贝安装路径的Docs文件夹下,注意在定义变量的时候使用了通配符
第二步,如果拷贝成功,则返回值为0,那么进行下一步相应操作
************************************************************************************** nResult = FindAllFiles(TARGETDIR^\
查找目标文件夹下所有后缀名为pdf的文件,从文件夹的开始位置进行查找,查找成功则返回0。 这个函数在这里有一个巧妙的应用,因为这个函数会在查找到第一个符合条件的文件时就会停止继续向下查找,因此利用静态变量的传值不同,来实现对文件夹的全部查找。 Help里的解释如下:
FindAllFiles ( szDir, szFileName, svResult, nOp );
参数一:szDir,被查找的文件夹
参数二:szFileName,需要查找的文件的名字,支持通配符,例如*.*,*.pdf,*.doc
参数三:svResult,函数会在查找到第一个符合条件的文件时停止,返回这个符合条件的文件的文件名,带全路径和含扩展名的文件名
参数四:nOp,静态变量。CONTINUE,从上一次查找的位置开始查找,这个特性我们呆会儿会用到;RESET,从文件夹的开始位置进行查找;CANCEL,释放被上一次的FindAllFiles查找的函数。在Windows NT系统下,需要在安装过程中使用带CANCEL的FindAllFiles来释放之前的查找,确保安装的正确性(因此我怀疑查找有bug,这个函数用来弥补这个bug…)。 ************************************************************************************** LongPathToQuote(szDocFile, TRUE );
szDocFile为上一个函数查找到的第一个符合条件的文件名,带完整路径,这个LongPathToQuote函数加上这个文件名上的括号;否则下面一个函数无法解析不带括号的长文件名。
Help里的解释如下:
LongPathToQuote ( svPath, nParameter ); 参数一:svPath,长文件名
参数二:nParameter,静态变量。 TRUE,为长文件名加上括号;FALSE,为长文件名脱去括号。 ************************************************************************************** ParsePath (szDocFileName, szDocFile, FILENAME_ONLY); 解析带路径的长文件名,返回文件本身的文件名 Help里的解释如下:
ParsePath ( svReturnString, szPath, nOperation );。 参数一:svReturnString为返回的解析过的文件名, 参数二:szPath,即被解析的长文件名
参数三:nOperation,静态变量,指定用何种方式来解析。这里使用FILENAME_ONLY,也就说返回值为不带路径、不包含扩展名的文件名。这个文件名被下面一步用作显示的快捷方式的名称。 **************************************************************************************
AddFolderIcon(FOLDER_PROGRAMS^\TARGETDIR^\ 创建一个快捷方式,使用指定的图标。 Help里的解释如下:
AddFolderIcon ( szProgramFolder, szItemName, szCommandLine, szWorkingDir, szIconPath, nIcon, szShortCutKey, nFlag );
参数一:szProgramFolder,要创建的快捷方式所在的文件夹。这里FOLDER_PROGRAMS指开始 | 所有程序,因此我们的快捷方式将会出现在开始 | 所有程序 | Test的Docs下;如果要添加到桌面上,可以设置为FOLDER_DESKTOP;FOLDER_STARTUP 指添加为启动项;FOLDER_STARTMENU添加到开始菜单下。
参数二:szItemName,help里解释很晦涩,解释为要添加到文件夹下的图标的名称,即出现的图标旁边的那个字符串。其实就是我们常说的快捷方式的名称。这里填写被解析出来的那个不带路径也不带扩展名的文件名。
参数三:szCommandLine,全限定路径的文件名或文件夹名,可包含命令行参数。这里传入刚才查找到的文件名,包含路径、文件名和扩展名。读者可能注意到这个参数被做了一些预处理,这个处理也是折腾了几次才搞出来的,不同的操作系统默认路径也是有是否带引号的差别的,这里需要显式地指定一下,以免在不同操作系统上运行时引起不同的结果。
参数四:szWorkingDir,工作目录。Help里的解释如下:设置这个目录为你的应用程序文件所在的地方;要设置包含了应用程序的目录为工作目录,则可传一个空字符串给这个参数。这个参数一开始我并未理解其含义,不过传空字符串也没有出错;在后来经理提出新要求:允许用户自行选择是否在桌面上创建快捷方式时无意中明白这个参数的含义;请读者随便寻找一个自己计算机上的任意位置的快捷方式,右键点击选择“属性”,这个szWorkingDir就是属性面板上的“起始位置”,值为这个快捷方式所指的应用程序所在的文件夹的路径。至少在我试验的程序里,创建开始菜单的快捷方式和桌面快捷方式,这个参数要求的值还是略有不同的,开始菜单里创建,可以直接传空字符串;而桌面快捷方式,传控字符串总是会出错,查看属性面板里的“起始位置”值为空,因此手动地传了快捷方式所指向的应用程序的所在文件夹的路径,后面在“安装结束时允许用户选择创建桌面快捷方式”话题里有详细说明。
参数五:szIconPath,带全限定名的图标的路径,即包含路径、文件名和扩展名
参数六:nIcon。如果不是使用Windows图标的话,统统指定为0;Windows图标我没有研究过,Help里说可以指定为0,1,2,3…n我猜测是不是图标文件本身包含了多个图标,而我可以指定使用哪个图标? 参数七:szShortCutKey,热键,一般用不到。如果有需要可以设置为比如\这种形式。 参数八:nFlag,静态变量,多个用途。这个程序里我们使用了REPLACE,即永远使用当前这个快捷方式的属性;RUN_MAXIMIZED ,当从这个快捷方式登录程序时,程序界面最大化;
RUN_MINIMIZED,当从这个快捷方式登录程序时,程序界面最小化; NULL,无任何操作(不知道这个无任何操作适用于何种情况?)。 小结:这段代码的重点在于
1) 实现对文件夹下的文件的遍历。因为之前笔者的文档都打包在程序里,苦于文档的名称和数量常常变更,每做一次都要耗费人力物力,而且在光盘里仍然需要单独放置一个文档文件夹供用户在没有安装程序前的随时查看,重复打包安装使得安装内容容量巨大,以至于从刻录小光盘改成刻录大光盘,从VCD盘改成DVD盘。这段代码在用户选择了安装文档的条件下,对外部文件夹进行
了拷贝,并且读取文件夹下所有的pdf文件(依次类推,只要设置了正确的过滤条件,可以读取文件夹下想要的文件)。难点就在于将文件夹下的文件一个个读取出来并且获取该文件的信息。 2) 对读取的文件创建快捷方式,这个难点在于8个参数的理解。我在互联网上搜索了一阵子,并且啃了一阵子help,但是可能自己外语水平不是很过关,以至于第四个参数没有完全理解到底是什么意思,所见的例子也很单调并且偷懒,能赋””的地方都给赋了””,无语~~~~ 整个安装程序做下来这一段代码是最难的,FindAllFiles在Help里解释是当碰到第一个符合条件的文件就会停下来,因此如何读取全部文件,并且获取文件信息,代码的撰写也是费了很大的功夫,并且参考了别人的程序修改出来的。
6. 在安装结束时,显示readme.txt文件
这是个很有用的设置,但是在InstallScript工程里不是默认自带的,因此也需要脚本编程实现。 这段代码的位置是在After Move Data | OnFirstUIAfter()的函数里实现的
1. 首先,在安装的时候把readme.txt文件从源盘拷贝到安装目录下。把这段代码拷贝到After Move Data | OnFirstUIAfter()的begin和end;之间即可。README.TXT文件放置在源盘的根目录下,并且在安装时拷贝到安装目录下。
CopyFile(SRCDISK^\ 这段代码意味着当安装执行的时候,这个文件总会被拷贝过去。
2. 创建一个Finish界面,并在界面上设置询问是否显示readme.txt文件的选项。
之前我们看到当我们第一次选取了After Move Data | OnFirstUIAfter()选项时,系统会为我们创建如下代码(当然不创建也不要紧,自己敲就是了) 这个就是结束界面。Installscript工程默认安装完毕后,界面直接消失,而不会出现一个带有Finish按钮的界面让用户点击了以后才结束整个安装过程。
这段代码就是创建了一个Finish界面了,我们要对这段代码进行改造,使之出现一个是否显示readme的选项。
把上图中从Disable(STATUSEX);起到SdFinishEx这行的代码,全部替换成如下代码: Disable(STATUSEX);
ShowObjWizardPages(NEXT); bOpt1 = TRUE;
bOpt2 = TRUE;
szMsg1 = SdLoadString(IFX_SDFINISH_MSG1); szTitle=\ szMsg1=\ szMsg2=\
szOption1=\ szOption2=\
SdFinishEx(szTitle, szMsg1, szMsg2, szOption1, szOption2, bOpt1, bOpt2); if (bOpt1=TRUE) then
if(FindFile(TARGETDIR, \
LaunchApp ( WINDIR^\ endif; endif;
3. 代码解释
******************************************************************************************* Disable(STATUSEX);
使默认的安装设置对话框无效。
******************************************************************************************* ShowObjWizardPages(NEXT);
顺序执行这个OnFirstUIAfter()的代码,如果参数为BACK,则逆序执行
******************************************************************************************* SdLoadString(IFX_SDFINISH_MSG1);
返回参数所关联的字符串值,这个参数应当是一个资源ID。
******************************************************************************************* SdFinishEx(szTitle, szMsg1, szMsg2, szOption1, szOption2, bOpt1, bOpt2); 参数一:szTitle,即显示在界面上的左上角的标题,如果传空值,则显示默认值
参数二:szMsg1,安装结束的界面上允许最多有两个可选项,这个参数可以显示第一个选项的一些相关说明,如果赋空则不显示任何说明
参数三:szMsg2,解释同上
参数四:szOption1,选项名。这个是一个Checkbox,如果设置为空则不显示,如果赋值则显示一个Checkbox并且在这个Checkbox旁边显示这个所赋的简短值。 参数五:szOption2,解释同上。 参数六:第一个选项的状态,如果设置为TRUE,则第一个选项Checkbox默认为选中状态,FALSE则为未选中状态。
参数七:第二个选项的状态,解释同上。
******************************************************************************************* if (bOpt1=TRUE) then
判断是否选择了checkbox。如果用户选择了这个选项,则进行下一步操作 ******************************************************************************************* if(FindFile(TARGETDIR, \
为了保险起见,需要进一步判断一下这个readme.txt是否被拷贝进来了 Help里解释如下:
FindFile ( szPath, szFileName, svResult );
参数一:szPath,文件所在的路径,不包含文件名 参数二:szFileName,文件名,包含扩展名 参数三:szDocFile,返回的文件名
如果查找成功,则返回值为1
******************************************************************************************* LaunchApp ( WINDIR^\ 打开readme文件
Help里没有对这个函数的专门的解释,但是有个例子,以至于我看了好几遍才看懂要表达的意思 参数一:应用程序,也就是你用什么工具来打开第二个参数指定的文件。我们这里用记事本打开,因此要引用一下Windows下自带的程序Notepad.exe,路径为WINDIR^\。如果是一些不是Windows自带的程序,比如PDF,DOC,还需要从注册表里得到所安装的目标位置,从这个目标位置得到要用的工具。有兴趣的朋友可以试验一下。 参数二:要打开的文件,带路径,包含扩展名
小结:这个界面我曾经试图写在OnFirstUIBefore()里的结尾部分,用Dlg_SdFinish来实现,但是总是发现虽然结束界面能出来,但是上一个界面不能消失掉的情况。因为这个资料也不好找,仓促之间试验出上述所说的办法,估计是等安装界面结束后补上一个界面来达到这个效果的;其实我本人是比较讨厌结束的时候有这么一个要看readme的选项的,一般自己装到这种软件,都是去掉钩选框,不看readme的;但是如果直接结束掉,不出这个结束界面又觉得提示不足,有时候不能确
定安装程序有没有结束,所以私下里还是比较想去掉readme选项,而直接显示一个只有一个finish按钮的界面的。
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=\
szOption2=\
SdFinishEx(szTitle, szMsg1, szMsg2, szOption1, szOption2, bOpt1, bOpt2); 2. 代码解释
与上面的“显示readme文件”中的代码相比,只动了一个地方,即szOption2=\Desktop?\
这个是一个Checkbox,如果值设置为空则不显示,如果赋值则显示一个Checkbox并且在这个Checkbox旁边显示这个所赋的简短值。
这里我们需要它显示出来,这样在界面上用户就会看到一个钩选框询问是否要显示桌面快捷方式。 3. 接下来我们要对用户所做的选择做一些判断,并且显示桌面快捷方式,在这段代码后面加上 if(bOpt2=TRUE) then
if (FeatureIsItemSelected(MEDIA, szFeatureName1)=1) then szDocFile = TARGETDIR^\ LongPathToQuote(szDocFile, TRUE );
AddFolderIcon(FOLDER_DESKTOP, \TARGETDIR^\ endif;
4. 代码解释
因为上面对这些函数的每个参数都有详细解释了,所以这里就不做一一解释了,只对要注意的地方做说明。
这里,一开始,笔者对第四个参数仍然传的是空字符串,但是创建的快捷方式总是不能运行,对比属性面板才发现,桌面快捷方式的“起始位置”的值居然是空的,看来Help解释的“当传空值的时候,默认为快捷方式所指的应用程序所在的目录”并未生效,只好老老实实地把运行目录的值手动地传进去。
读者可能注意到在AddFolderIcon函数里的第三个参数被做了一些预处理,这个处理也是折腾了几次才搞出来的,不同的操作系统默认路径也是有是否带引号的差别的,这里需要显式地指定一下,以免在不同操作系统上运行时引起不同的结果。
8. 在安装结束后,启动指定的程序