在本地网络环境中,应用程序的更新常常是一项耗时的任务,尤其是当应用程序分布在多个客户端上,并且更新频繁时。为了解决这个问题,编写了一个简单的函数,它能够在不需要用户干预的情况下自动检测应用程序的新版本并进行安装。
实现这一功能的前提是应用程序的安装文件(.msi)需要放置在一个预设的网络文件夹中,以便每个客户端都能够访问并检查它。
应用程序的主函数需要通过包含下面的代码进行修改。现在,当客户端启动应用程序时,代码会检查.msi文件是否包含新版本,如果是这样:
如果安装文件的文件日期至少比可执行文件(.exe)的文件日期晚两分钟,则认为安装文件是更新的(这是一个简单的方法,但很有效)。
由于应用程序在运行时无法卸载自身,它需要退出自身并调用一个批处理文件来完成卸载/安装工作。这个批处理文件由程序直接生成并放置在临时文件夹中。它看起来像这样:
@echo off
ping localhost -n 2
C:\WINDOWS\system32\msiexec.exe /x {67BC5B51-1534-4C68-86C4-C74F4469C2BA} /qr
C:\WINDOWS\system32\msiexec.exe /i "Z:\setup\MyAppSetup.msi" /qr
cd "C:\Program Files\Myapp"
start "" "C:\Program Files\Myapp\MyApp.exe"
第2行的ping命令用于在卸载前增加一个小的延迟,以确保调用的应用程序已经终止。使用ping命令是因为Windows没有标准的命令来引入延迟(例如,sleep命令)。
第3行使用Windows Installer(/x开关)卸载旧版本的应用程序。/qr开关最小化用户界面。
第4行安装应用程序的新版本。
在第5行和第6行,应用程序再次启动,提供相同的工作文件夹和相同的命令行参数(如果有的话)。start命令用于使批处理文件继续执行,而不需要等待应用程序完成。
所有工作都在一个名为CheckApplicationUpdate()的函数中完成,需要将这个函数复制并粘贴到应用程序的主程序中。这个函数需要在Application.Run()之前调用,例如:
C#
static
void
Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(
false
);
//
add the following line to your main
if
(CheckApplicationUpdate())
return
;
//
update is needed, quit
Application.Run(
new
Form1());
}
CheckApplicationUpdate()需要通过修改三个字符串来定制:
C#
static
bool
CheckApplicationUpdate()
{
string
InstallFile =
"
Z:\\setup_folder\\MyApp.msi"
;
string
BatName =
"
c:\\windows\\temp\\update.bat"
;
string
ProductCode =
"
{67BC5B51-1534-4C68-86C4-C74F4469C2BA}"
;
InstallFile
是更新安装包放置的位置;通常,它是一个网络文件夹,以便所有客户端都可以访问。
BatName
是由程序生成的临时批处理文件,用于执行所有的安装/卸载工作。
ProductCode
是应用程序的产品代码,可以直接从应用程序的设置属性页获得。
整个函数:
C#
static
bool
CheckApplicationUpdate()
{
//
location of setup file
string
InstallFile =
"
Z:\\setup_folder\\MyApplication.msi"
;
//
name of the .bat file that does the uninstall/install
string
BatName =
"
c:\\windows\\temp\\update.bat"
;
//
product code of the application
string
ProductCode =
"
{67BC5B51-1534-4C68-86C4-C74F4469C2BA}"
;
//
if install file is not available skip the whole process
if
(!File.Exists(InstallFile))
return
false
;
//
calculates the time difference betwenn install package and executable
DateTime EXE_Stamp = Directory.GetLastWriteTime(Application.ExecutablePath);
DateTime MSI_Stamp = Directory.GetLastWriteTime(InstallFile);
TimeSpan diff = MSI_Stamp - EXE_Stamp;
//
if installable is newer than 2 minutes, does the new install
if
(diff.Minutes >
2
)
{
string
msg =
"
A new version of "
+Application.ProductName+
"
is available.\r\n\r\nClick OK to install it."
;
MessageBox.Show(msg,
"
Updates available"
,
MessageBoxButtons.OK,
MessageBoxIcon.Information);
//
prepares the batch file
string
BatFile =
"
"
;
string
old_dir = Directory.GetCurrentDirectory();
BatFile +=
"
@echo off\r\n"
;
BatFile +=
"
ping localhost -n 2\r\n"
;
BatFile +=
"
C:\\WINDOWS\\system32\\msiexec.exe /x "
+
ProductCode+
"
/qr \r\n"
;
BatFile +=
"
C:\\WINDOWS\\system32\\msiexec.exe /i \""
+
InstallFile+
"
\" /qr\r\n"
;
BatFile +=
"
cd \""
+old_dir+
"
\"\r\n"
;
BatFile +=
"
start \"\" "
+
Environment.CommandLine+
"
\r\n"
;
StreamWriter sw =
new
StreamWriter(BatName);
sw.Write(BatFile);
sw.Close();
//
executes the batch file
System.Diagnostics.ProcessStartInfo psi =
new
System.Diagnostics.ProcessStartInfo();
psi.FileName = BatName;
psi.Arguments =
"
"
;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
System.Diagnostics.Process p =
new
System.Diagnostics.Process();
p.StartInfo = psi;
p.Start();
return
true
;
}
return
false
;
}