资源描述
安装前
设立界面公司标记
在OnBegin函数中,添加如下脚本:
SetTitle(IFX_PRODUCT_NAME + "-Infomedia", 0, BACKGROUNDCAPTION);
安装中
安装.net
RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
if(RegDBKeyExist("SOFTWARE\\Microsoft\\.NETFramework\\policy\\v4.0")<0)then
if(AskYesNo("尚未安装.net framework4.0!\n是否安装?",YES))then
if(LaunchAppAndWait(SUPPORTDIR^"dotNetFx40_Full_x86_x64_en.exe"," /norestart",WAIT)<0)then
SprintfBox(MB_OK,".NET安装","安装.net框架发生意外!");
else
InstallNet=TRUE;
endif;
else
InstallNet=FALSE;
endif;
else
endif;
注:InstallNet在开始定义BOOL类型
修改OnFirstUIAfter中的脚本
以判断是否重启。
vbs控制IIS
直接使用 adsutil.vbs IIS自带的脚本来做的.基本上IIS的所有操作都可以用这个脚本完毕.目录在C:\inetpub\AdminScripts
ServerManagerCmd.exe 管理安装服务器角色
参数名称:
修改IIS中ISAPI和CGI限制
%windir%\\system32\\inetsrv\\appcmd.exe set config /section:isapiCgiRestriction /[path='C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll'].allowed:True
控制文本框
自定义界面,假如控制文本框
此时,当选择文本框时,便可取消其它选项的状态。
多语言安装
不同语言的安装文献放到不同的Components里,然后设立相应的安装语言条件即可
获取安装环境语言
获取Version信息
读取ProductVersion Property
Installshield获取安装包版本的系统变量为IFX_PRODUCT_VERSION
打开对话框的时候按某个途径打开
打开某一个途径的文献夹用这个函数 ShowProgramFolder ( szFolder, nCommand );
判断服务状态
ServiceGetServiceState
Installshield环境变量的追加与删除
====== 环境变量的追加与删除 ======
====== 环境变量的添加或追加 ======
* 问题:如何能在安装包中添加环境变量,而不用用户手动在我的电脑/属性/高级/环境变量中设立,特别是,如何能判断已有的环境变量,如Path,在不改变已有的环境变量的内容的基础上,进行追加呢?
* 解决方案:添加环境变量时,可以通过注册表中相应位置写键值的方式完毕:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment.
一方面判断Path是否存在,假如不存在,创建,假如存在,已有的内容进行追加。追加的方法参考如下代码:
function AddPath()
NUMBER nResult,nType,nSize,nvSize,nvType;
STRING strResult,szkey,szNumName,szNumValue,nRootKey,szPath,szPath2;
STRING TITLE, szFormat;
begin
RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
szkey="SYSTEM\\ControlSet001\\Control\\Session Manager\\Environment";
// has no the key, then create the key
if (RegDBKeyExist(szkey) < 0)then
if (RegDBCreateKeyEx(szkey, "") < 0) then
MessageBox ("RegDBCreateKeyEx failed.", SEVERE);
return FALSE;
endif;
endif;
//添加系统途径
RegDBGetKeyValueEx(szkey,"Path",nvType,szPath,nvSize);
if szPath!="" then
PathSet(szPath);
if (PathAdd(TARGETDIR^"\\scratch\\bin", "", FULL, AFTER) < 0) then
MessageBox ("Unable to add to path buffer.", SEVERE);
abort;
endif;
PathGet(szPath);
Disable(LOGGING);
if (RegDBSetKeyValueEx(szkey,"Path",REGDB_STRING,szPath,-1) < 0) then
MessageBox ("RegDBSetKeyValueEx failed.", SEVERE);
return FALSE;
endif;
Enable(LOGGING);
else
szPath=TARGETDIR^"\\scratch\\bin";
// Set a key name and a value associated with it.
Disable(LOGGING);
if (RegDBSetKeyValueEx(szkey,"Path",REGDB_STRING,szPath,-1) < 0) then
MessageBox ("RegDBSetKeyValueEx failed.", SEVERE);
return FALSE;
endif;
Enable(LOGGING);
endif;
end;
====== 卸载时如何删除追加的环境变量的问题 ======
* 问题:安装包卸载时,如何能不改变已有的环境变量的内容,只是删除追加的环境变量?
* 解决方案:参考如下,特有的关键字删除即可,案参考以下代码片段,即可实现。
function DelPath()
NUMBER nResult,nType,nSize,nvSize,nvType;
STRING strResult,szkey,szNumName,szNumValue,nRootKey,szPath,szPath2;
begin
RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
szkey="SYSTEM\\ControlSet001\\Control\\Session Manager\\Environment";
//添加系统途径
RegDBGetKeyValueEx(szkey,"Path",nvType,szPath,nvSize);
if szPath!="" then
PathSet (szPath);
PathDelete ("scratch", PARTIAL);
endif;
end;
====== 追加方式的卸载问题 ======
问题:当卸载的时候,却发生了一件事情,那就是,本来系统已有的环境变量Path也被自动删除了,这会影响到其他软件的使用。
解决方案:本来,installsheild会记录所做的操作在log信息中,卸载时,会自动进行清理动作。
那么如何才干避免呢?RegDBSetKeyValueEx函数调用之前,可以先Disable(LOGGING);
调用之后,在Enable(LOGGING); 即可解决这个问题。
====== Dos命令无法使用的问题 ======
* 问题:所有的dos命令,如ping 不能使用了。
* 解决方案:在网上查找,只找到问题,没有搜索到解决方案,于是,只能一一查看Help,发现RegDBSetKeyValueEx的第三个参数引来的问题,需要修改第三个参数为REGDB_STRING_ EXPAND,由于在XP下,path具有一个%SystemRoot%的相对途径,假如使用了REGDB_STRING,所有的dos命令将都不能使用,此时,在dos下输入path一看,该替换成绝对途径的地方都没有替换掉,IS程序里键值设立时候的类型问题,REGDB_STRING是不结识相对途径的,换成REGDB_STRING_ EXPAND就可以了。
反复性安装basic MSI
用basic MSI的 工程,custom action and sequences里的maintenancewelcome中conditions设立为0,然后readyToInstall里设立成Not PATCH Or IS_MAJOR_UPGRADE
我就是用这个方法解决的
获取安装包途径
SETUPEXEDIR可以直接获得
反复性安装探讨
通过删除这两个CA,安装后注册表Unistall途径下只有一个安装值,并且为空
可以在安装完毕时,用脚本删掉即可实现Installscript MSI 工程的反复性安装,对于卸载,暂时没有更好的方法去实现(无非就是直接删除文献罢了)
显示安装进度内容
SetStatusWindow (-1, "正在。。。。,请稍候...");
MSU文献安装
if(FeatureIsItemSelected(MEDIA,szMediaServer)=1)then
if (SYSINFO.bIsWow64) then
LaunchAppAndWait("wusa.exe",TARGETDIR+"MediaServer\\Windows6.0-KB934518-x64-Server.msu",LAAW_OPTION_WAIT);
else
LaunchAppAndWait("wusa.exe",TARGETDIR+"MediaServer\\Windows6.0-KB934518-x86-Server.msu",LAAW_OPTION_WAIT);
endif;
endif;
LaunchAppAndWait 获取执行返回值
Uac
安装后
安装重启后继续安装
很多朋友做安装包的时候,所打包的软件需要.NET Framework之类的环境,他们会检测系统是否已经安装了.NET,假如没有,则调用.NET安装包来安装。但是.NET安装完是需要重启动的,一般来说,我们都推荐使用/q/norestart的静默安装函数来使重启动推迟到安装结束时,使用如下:
LaunchAppAndWait(SUPPORTDIR^"dotNetFx40_Full_x86_x64.exe","/q /norestart",WAIT);
.NET在重启后才干生效,但是假如在安装完.NET之后的安装行为中立刻需要使用.NET特性,那么必须让先电脑重新启动,但是重启后让用户再次点击setup.exe来继续安装是不和谐的行为,假如可以在重启后自动调用安装包继续下一步安装,那该多么好啊。
因此我的想法是:将setup.exe的途径写入到
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
键值下,这样会在你的电脑重启后,自动运营你的setup.exe来继续安装。
记得在安装结束时,写脚本来删除这个键值,不然每次电脑开机都要运营这个setup.exe啦
安装完毕调用重启界面
修改OnFirstUIAfter()函数里的脚本:
安装后刷新环境变量
#define WM_WININICHANGE 0x001A
#define HWND_BROADCAST 0xffff
szEnv = "Environment";
pEnv = &szEnv;
SendMessage (HWND_BROADCAST, WM_WININICHANGE, 0, pEnv );
卸载
自动编译、打包
版本机,SVN,融合起来,自动编译和打包 容易了就。
TFS的没有弄过。我们用的是SVN,将SVN、CruiseControl和Installshied整合在一起,天天检查更新、自动集成、编译,然后打包
C# 自动编译com
加ISWiAutomation19.dll 引用 然后 var proj = new ISWiAuto19.ISWiProject();
proj.OpenProject(projPath);
proj.ProductVersion = version;
proj.SaveProject(); 用前Regsvr32 ISWiAutomation19.dll /i
c#的项目 build 标签中 platForm target 要选x86
错误解决
安装完毕时提醒1603错误
启动两个服务:
LaunchAppAndWait("","net start \"WebManagementService\"", LAAW_OPTION_WAIT|LAAW_OPTION_HIDDEN);
LaunchAppAndWait("","net start aspnet_state",LAAW_OPTION_WAIT|LAAW_OPTION_HIDDEN);
记录安装日记
合用工程
Basic MSI, InstallScript MSI
操作系统
所有的Windows
摘要
要产生一个记录安装过程的日记文献,需要在命令行模式下用/l运营MSI包。日记文献可被用来诊断安装失败或未定义行为的因素。
详述
要记录MSI安装包的运营过程,你需要使用/l(可随着更多开关使用,见下表),同时也需要提供日记文献途径(注意必须为绝对途径)。
下面的例子表白如何产生一个日记文献以包含最具体的安装日记信息。
msiexec /i "C:\my stuff\package.msi" /l*v "d:\place for logs\package.log"
下表是可以和/l一起使用的开关
Modifier Description
i
Status messages - Indicates when actions are started and stopped.
w
Non-fatal warnings
e
All error messages
a
Start up of actions
r
Action-specific records
u
User requests
c
Initial UI parameters
m
Out-of-memory or fatal exit information
o
Out-of-disk-space messages
p
Terminal properties
v
Verbose output
x
Extra debugging information--only available on Windows Server 2023
+
Append to existing file
!
Flush each line to the log
*
Wildcard, log all information except for the v and x options. To include the v and x options, specify "/l*vx".
其他示例
Keep track of the sequence in which actions start and stop during uninstallation:
msiexec /x {00010001-0001-0001-0001} /li "d:\logdir\package.log"
仅记录错误:
msiexec /i "C:\my stuff\package.msi" /le "d:\place for logs\package.log"
Log events that are more minute in scope than the actions 并记录内存局限性和磁盘空间错误:
msiexec /jm "C:\my stuff\package.msi" /lvmo "d:\place for logs\package.log"
再安装结束时获得一份所有属性和其值的列表,但是追加到package.log中(而非替换之)
msiexec /i "C:\my stuff\package.msi" /lp+ "d:\place for logs\package.log"
通过setup.exe产生MSI运营日记
假如你无法直接访问MSI文献(比如只有单一的压缩的setup.exe),你可以使用setup.exe的/v开关来传递参数给msiexec。值得注意的是日记记录只会MSI的运营记录,而不会记录来自setup.exe自身的动作(以及instmsia.exe或者instmsiw.exe自身的动作)。
注意点:
1. 在/v和他的参数间不能有空格。
2. 整个参数必须被引号包围。
3. 参数中假如有引号,则需要使用用转义符\。
下面的例子表白如何使用setup.exe产生一个日记文献以包含最具体的安装日记信息
setup.exe /v"/l*v \"d:\place for logs\package.log\""
注意工程文献去掉只读属性
卸载失败提醒错误
在
改为YES即可
升级
安装解释
在InstallShield的高级培训课程中,我们常谈到的掌握MSI工程的四大核心内容,其中Condition就是其中之一。
今天我们对Condition再次做一个总结:
初次安装:Not Installed
修改,修复或删除:Installed
删除(卸载):REMOVE
维护或修复:Installed AND Not REMOVE
小版本升级:IS_MINOR_UPGRADE
大版本升级:IS_MAJOR_UPGRADE
上述合用于InstallShield的Basic MSI工程和InstallScript MSI工程。
安装卸载旧版本(淘宝)
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 2023.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脚本完毕安装新版本前卸载老版本的方法, 假如大家有其他好的方法,请多多指教。
原文链接
自带更新升级问题汇总
1.当安装程序需要删除一些文献的时候,需要做Major Upgrade,新安装之前必须卸载旧版本
2.Dll文献升级必须更改版本号
注册表相应的反映
"HKLM\SOFTWARE\Classes\Installer\Products\5BDC99C4525D2B
展开阅读全文