WinForm应用程序中实现自动更新功能
编写人:左丘文
2015-4-20
近来在给一客户实施ECM系统,但他们使用功能并不是我们ECM制造版提供的标准功能,他们要求对系统作一些定制功能,为了避免因程序的bug而带来频繁让用户更新程序的不良影响,就想给ECM增加一个winform自动更新功能,今天在这里,我想与大家一起分享代码,在此做个小结,以供参考。有兴趣的同学,可以一同探讨与学习一下,否则就略过吧。
1、 首先我们在这里先分析一下其它程序猿的一些基本情况:
相信有许多程序猿都喜欢用Winform做开发吧?!因为Winform相对Webform而言,优点是,功能更强大,编程更方便.但是它的缺点,就是软件的安装及维护是相当麻烦地,要实现软件更新,需要到客户端一台一台地升级。
长期以来,广大程序猿为到底是使用Client/Server,还是使用Browser/Server结构争论不休,在这些争论当中,C/S结构的程序可维护性差,布置困难,升级不方便,维护成本高就是一个相当重要的因素。有很多企业用户就是因为这个原因而放弃使用C/S。然而当一个应用必须要使用C/S结构才能很好的实现其功能的时候,我们该如何解决客户端的部署与自动升级问题?部署很简单,只要点击安装程序即可,难的在于每当有新版本发布时,能够实现自动升级。现在好了,我们的目标很简单,我们希望开发一个与具体应用无关的能够复用的自动升级系统。下面我为大家提供了一套可复用的用C#实现在线升级。这里分为本地在线升级,也可以利用webservice 在线通过互联网与软件开商的服务器在线升级。
2、 实现软件自动在线升级的原理:
1) 写三个程序,一个是主程序;两个是升级程序;所有升级任务都由升级程序完成
原本只需要一个升级程序,但在这里,由于我们另外还涉及到了,在线与软件供应商服务器更新功能,因此我们这里用到了一个主程序两个升级程序。
2) 很多人实行的原理是将现有版本与最新版本作比较,发现最新的则提示用户是否升级,当然也有人用其它属性比较的,例如:文件大小或者更新日期。我们这里主要利用FileUtil的两个属性SHA1File与MD5File来判断,与服务器之间是否存在版本差异,存在就更新。
3) 我们的程序,刚开始初始版本是我一同事利用了三天时间,大致写了一个框架出来,我是在他的基础上,对其进行了完善,如增加了对文件流的压缩与解压缩功能,方便进行网络的传输,增加了通过webservices的在线更新功能。并将程序做到通用功能,并嵌套到了我们的ECM系统中。
3、 软件更新操作界面:
1) 启动我们的主程序ECM
2) 系统会从数据库中检查是否有新版本,点点【否】会直接进入系统,点【是】系统会进入到更新介面:
先择需要更新的内容,点击更新,系统会自动更新相关程序。
3) 与软件供应商服务器在线更新介面:
操作类似于在线本地更新一样。
具体就需要各位好好的自已去调试了。
4、 更新程序的代码:
1) 我们的更新程序是以文件流的形式存放在数据库中,因此我们首先需要为系统数据库增加相关的表,用于存储更新文件。
--建立相关表
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[SysUpdate](
[ID] [int] IDENTITY(1,1) NOT NULL,
[FileName] [varchar](250) NULL,
[FileVersion] [varchar](50) NULL,
[FilePath] [varchar](250) NULL,
[FileData] [varbinary](max) NULL,
[FileSize] [varchar](250) NULL,
[FileDate] [varchar](250) NULL,
[FileType] [varchar](50) NULL,
[FilesHash] [varchar](max) NULL,
[FilesMD5] [varchar](max) NULL,
[UpdateBit] [bit] NULL,
[RegBit] [bit] NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
--建立插入SP
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create procedure [dbo].[Insert_UpdateFile] @filename varchar(250),@fileversion varchar(50),@filepath varchar(250),@filesize varchar(250),@filedate varchar(250),@filetype varchar(50),@fileshash varchar(250),@filesmd5 varchar(250),@file varbinary(Max)
as
insert into SysUpdate ([FileName],[FileVersion],[FilePath],[FileSize],[FileDate],[FileType],[UpdateBit],[RegBit],[FilesHash],[FilesMD5],[FileData])
select @filename,@fileversion,@filepath,@filesize,@filedate,@filetype,1,0,@fileshash,@filesmd5,@file
2) 整体程序框架图如下:
3) 上传功能代码:
namespace SysUpdate
{
public partial class frmSysUpdateUp : Form
{
private string updateUrl = string.Empty;
private string tempUpdatePath = string.Empty;
WinBase.Common W1 = new WinBase.Common();
public frmSysUpdateUp()
{
InitializeComponent();
}
private void frmSysUpdateUp_Load(object sender, EventArgs e)
{
//数据库SysUpdate表 显示需要更新内容
dgvList.ColumnCount = 9;
dgvList.AutoGenerateColumns = false;
DataGridViewCheckBoxColumn newColumn = new DataGridViewCheckBoxColumn();
DataGridViewCheckBoxColumn newColumn1 = new DataGridViewCheckBoxColumn();
DataGridViewCheckBoxColumn newColumn2 = new DataGridViewCheckBoxColumn();
dgvList.Columns.Insert(0, newColumn);
dgvList.Columns.Insert(10, newColumn1);
dgvList.Columns.Insert(11, newColumn2);
this.SetdgvListHeadText();
string strSQL41 = "SELECT * FROM SysUpdate order by ID;";
DataSet ds = W1.DS(strSQL41, "Sys");
dgvList.DataSource = ds.Tables[0].DefaultView;
this.DataBinding();
dgvList.Columns[0].Frozen = true;
dgvList.Columns[1].Frozen = true;
dgvList.Columns[2].Frozen = true;
dgvList.Columns[3].Frozen = true;
// dgvList.Columns[4].Frozen = true;
}
private void SetdgvListHeadText()
{
dgvList.Columns[0].HeaderText = "选择";
dgvList.Columns[0].Width = 50;
dgvList.Columns[1].HeaderText = "ID";
dgvList.Columns[1].Width = 20;
dgvList.Columns[1].ReadOnly = true;
dgvList.Columns[2].HeaderText = "组件名";
dgvList.Columns[2].Width = 120;
dgvList.Columns[2].ReadOnly = true;
dgvList.Columns[3].HeaderText = "版本号";
dgvList.Columns[3].Width = 80;
dgvList.Columns[3].ReadOnly = true;
dgvList.Columns[4].HeaderText = "大小";
dgvList.Columns[4].Width = 100;
dgvList.Columns[4].ReadOnly = true;
dgvList.Columns[5].HeaderText = "创建日期";
dgvList.Columns[5].Width = 150;
dgvList.Columns[5].ReadOnly = true;
dgvList.Columns[6].HeaderText = "哈希值";
dgvList.Columns[6].Width = 250;
dgvList.Columns[6].ReadOnly = true;
dgvList.Columns[7].HeaderText = "MD5值";
dgvList.Columns[7].Width = 250;
dgvList.Columns[7].ReadOnly = true;
dgvList.Columns[8].HeaderText = "目录";
dgvList.Columns[8].Width = 80;
dgvList.Columns[8].ReadOnly = true;
dgvList.Columns[9].HeaderText = "文件类型";
dgvList.Columns[9].Width = 80;
dgvList.Columns[9].ReadOnly = true;
dgvList.Columns[10].HeaderText = "是否更新";
dgvList.Columns[10].Width = 80;
// dgvList.Columns[10].ReadOnly = true;
dgvList.Columns[11].HeaderText = "是否需要注册";
dgvList.Columns[11].Width = 110;
//dgvList.Columns[11].ReadOnly = true;
}
private string Byte2String(byte[] arrByte)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in arrByte)
{
sb.Append(b > 15 ? Convert.ToString(b, 16) : ‘0‘ + Convert.ToString(b, 16));
}
return sb.ToString();
}
private void DataBinding()
{
// ID, FileName, FileVersion, FilePath, FileData, FileSize, FileDate, FileType, FilesHash, FilesMD5, UpdateBit, RegBit
dgvList.Columns[0].DataPropertyName = "Check1";
dgvList.Columns[1].DataPropertyName = "ID";
dgvList.Columns[2].DataPropertyName = "FileName";
dgvList.Columns[3].DataPropertyName = "FileVersion";
dgvList.Columns[4].DataPropertyName = "FileSize";
dgvList.Columns[5].DataPropertyName = "FileDate";
dgvList.Columns[6].DataPropertyName = "FilesHash";
dgvList.Columns[7].DataPropertyName = "FilesMD5";
dgvList.Columns[8].DataPropertyName = "FilePath";
dgvList.Columns[9].DataPropertyName = "FileType";
dgvList.Columns[10].DataPropertyName = "UpdateBit";
dgvList.Columns[11].DataPropertyName = "RegBit";
}
private void ListDate()
{
string strSQL41 = "SELECT * FROM SysUpdate order by ID ;";
DataSet ds = W1.DS(strSQL41, "Sys");
dgvList.DataSource = ds.Tables[0].DefaultView;
this.DataBinding();
}
private void btnUpload_Click(object sender, EventArgs e)
{
txtFileText.Text = "";
openFileDialog1.InitialDirectory = "d:\\";
openFileDialog1.Filter = "文件(*.*)|*.*";
openFileDialog1.FilterIndex = 1;
openFileDialog1.RestoreDirectory = true;
openFileDialog1.Multiselect = true;
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
txtFileText.Text = openFileDialog1.FileName;
//文件名称
String S = System.IO.Path.GetFileName(openFileDialog1.FileName);
//文件格式
// String FileType = System.IO.Path.GetExtension(openFileDialog1.FileName);
string SHA1 = "";
string md5 = "";
SHA1 = FileUtil.SHA1File(txtFileText.Text.ToString());//这个消息摘要可以用来验证数据的完整性
md5 = FileUtil.MD5File(txtFileText.Text.ToString());
try
{
if (FileUtil.IsInUse(txtFileText.Text.ToString()))
{
MessageBox.Show("文件已经使用中,无法上传!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
if (FileUtil.FileIsReadOnly(txtFileText.Text.ToString()))
{
FileUtil.SetFileReadonly(txtFileText.Text.ToString(), false);
}
FileStream fs = new FileStream(txtFileText.Text.ToString(), FileMode.Open);
int streamLength = (int)fs.Length; //获取文件流的长度。
byte[] image = new byte[streamLength]; //声明字节数组,用于保存图片文件
fs.Read(image, 0, streamLength); //把图片文件转换成为字节数组保存
fs.Close();
//文件版本号
FileVersionInfo fileVersion = FileVersionInfo.GetVersionInfo(txtFileText.Text.ToString());
FileInfo file = new FileInfo(txtFileText.Text.ToString());
// byte[] args0 = Common.SharpZip.CompressB(image);
byte[] args0 = Common.SharpZip.ICGzipCompress(image);
//创建文件流,path参数是文件路径
string strSQL2 = "exec Insert_UpdateFile ‘" + S + "‘,‘" + fileVersion.FileVersion + "‘,‘‘,‘" + file.Length + "‘,‘" + file.CreationTime + "‘,‘" + file.Extension + "‘,‘" + SHA1 + "‘,‘" + md5 + "‘,0x" + Byte2String(args0) + "";
//string strSQL2 = "exec Insert_UpdateFile ‘" + S + "‘,‘" + fileVersion.FileVersion + "‘,‘‘,‘" + file.Length + "‘,‘" + file.CreationTime + "‘,‘" + file.Extension + "‘,‘" + SHA1 + "‘,‘" + md5 + "‘,0x" + Byte2String(image) + "";
int k = W1.DC(strSQL2, "Sys");
if (k>0)
{
MessageBox.Show("成功!", "成功提示!", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("失败!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch
{
MessageBox.Show("文件插入数据库失败!文件可能正在占用!!","错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
ListDate();
}
}
private void dgvList_CellClick(object sender, DataGridViewCellEventArgs e)
{
// ID, FileName, FileVersion, FilePath, FileData, FileSize, FileDate, FileType, FilesHash, FilesMD5, UpdateBit, RegBit
txtID.Text = dgvList[1, e.RowIndex].Value.ToString();
txtFilePath.Text = dgvList[8, e.RowIndex].Value.ToString();
chkUpdateBit.Checked = Convert.ToBoolean(dgvList[10, e.RowIndex].Value);
chkRegBit.Checked = Convert.ToBoolean(dgvList[11, e.RowIndex].Value);
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
private void btnSave_Click(object sender, EventArgs e)
{
string strSQL2 = "Update SysUpdate set FilePath=‘" + txtFilePath.Text + "‘,UpdateBit=‘" + Convert.ToBoolean(chkUpdateBit.Checked) + "‘,RegBit=‘" + Convert.ToBoolean(chkRegBit.Checked) + "‘ where ID=‘" + txtID.Text + "‘; ";
int k = W1.DC(strSQL2, "Sys");
if (k > 0)
{
MessageBox.Show("更新成功!", "成功提示!", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("更新失败!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
ListDate();
}
private void btnDel_Click(object sender, EventArgs e)
{
string strSQL2 = "DELETE SysUpdate Where ID=‘" + txtID.Text + "‘; ";
int k = W1.DC(strSQL2, "Sys");
if (k > 0)
{
MessageBox.Show("删除成功!", "成功提示!", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("删除失败!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
ListDate();
}
private void dgvList_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
for (int i = 0; i < this.dgvList.Rows.Count; )
{
this.dgvList.Rows[i].DefaultCellStyle.BackColor = System.Drawing.Color.FromArgb(Convert.ToInt32(W1.LoadXmlFileValue("config.xml", "Color", "IMColor"))); ;// pParentWin.globalcolor2;
i += 2;
}
}
///<summary>
/// 序列化
/// </summary>
/// <param name="data">要序列化的对象</param>
/// <returns>返回存放序列化后的数据缓冲区</returns>
public static byte[] Serialize(object data)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream rems = new MemoryStream();
formatter.Serialize(rems, data);
return rems.GetBuffer();
}
/// <summary>
/// 反序列化
/// </summary>
/// <param name="data">数据缓冲区</param>
/// <returns>对象</returns>
public static object Deserialize(byte[] data)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream rems = new MemoryStream(data);
data = null;
return formatter.Deserialize(rems);
}
}
}
4) 本地在线更新功能代码:
namespace SysUpdate
{
public partial class frmLocalUpdate :Form
{
private string updateUrl = string.Empty;
private string tempUpdatePath = string.Empty;
WinBase.Common W1 = new WinBase.Common();
// private ECM.frmMain pParentWin = null;
bool isRun = false;
bool isUpdate = false;
string mainAppExe = "";
// public frmLocalUpdate(ECM.frmMain WinMain)
public frmLocalUpdate()
{
InitializeComponent();
// pParentWin = WinMain;
}
private void FrmSysUpdate_Load(object sender, EventArgs e)
{
//数据库SysUpdate表 显示需要更新内容
dgvList.ColumnCount = 10;
dgvList.AutoGenerateColumns = false;
DataGridViewCheckBoxColumn newColumn = new DataGridViewCheckBoxColumn();
DataGridViewCheckBoxColumn newColumn1 = new DataGridViewCheckBoxColumn();
DataGridViewCheckBoxColumn newColumn2 = new DataGridViewCheckBoxColumn();
dgvList.Columns.Insert(0, newColumn);
dgvList.Columns.Insert(11, newColumn1);
dgvList.Columns.Insert(12, newColumn2);
this.SetdgvListHeadText();
string strSQL41 = "SELECT * FROM SysUpdate order by ID ;";
DataSet ds = W1.DS(strSQL41,"Sys");
dgvList.DataSource = ds.Tables[0].DefaultView;
this.DataBinding();
dgvList.Columns[0].Frozen = true;
dgvList.Columns[1].Frozen = true;
dgvList.Columns[2].Frozen = true;
dgvList.Columns[3].Frozen = true;
// dgvList.Columns[4].Frozen = true;
DataCheck();
}
private void SetdgvListHeadText()
{
dgvList.Columns[0].HeaderText = "选择";
dgvList.Columns[0].Width = 50;
dgvList.Columns[1].HeaderText = "ID";
dgvList.Columns[1].Width = 20;
dgvList.Columns[1].ReadOnly = true;
dgvList.Columns[2].HeaderText = "组件名";
dgvList.Columns[2].Width = 120;
dgvList.Columns[2].ReadOnly = true;
dgvList.Columns[3].HeaderText = "服务器版本号";
dgvList.Columns[3].Width = 120;
dgvList.Columns[3].ReadOnly = true;
dgvList.Columns[4].HeaderText = "本地版本号";
dgvList.Columns[4].Width = 120;
dgvList.Columns[4].ReadOnly = true;
dgvList.Columns[5].HeaderText = "大小";
dgvList.Columns[5].Width = 100;
dgvList.Columns[5].ReadOnly = true;
dgvList.Columns[6].HeaderText = "创建日期";
dgvList.Columns[6].Width = 150;
dgvList.Columns[6].ReadOnly = true;
dgvList.Columns[7].HeaderText = "哈希值";
dgvList.Columns[7].Width = 250;
dgvList.Columns[7].ReadOnly = true;
dgvList.Columns[8].HeaderText = "MD5值";
dgvList.Columns[8].Width = 250;
dgvList.Columns[8].ReadOnly = true;
dgvList.Columns[9].HeaderText = "目录";
dgvList.Columns[9].Width = 80;
dgvList.Columns[9].ReadOnly = true;
dgvList.Columns[10].HeaderText = "文件类型";
dgvList.Columns[10].Width = 80;
dgvList.Columns[10].ReadOnly = true;
dgvList.Columns[11].HeaderText = "是否更新";
dgvList.Columns[11].Width = 80;
// dgvList.Columns[10].ReadOnly = true;
dgvList.Columns[12].HeaderText = "是否需要注册";
dgvList.Columns[12].Width = 110;
//dgvList.Columns[11].ReadOnly = true;
}
private void DataBinding()
{
// ID, FileName, FileVersion, FilePath, FileData, FileSize, FileDate, FileType, FilesHash, FilesMD5, UpdateBit, RegBit
dgvList.Columns[0].DataPropertyName = "Check1";
dgvList.Columns[1].DataPropertyName = "ID";
dgvList.Columns[2].DataPropertyName = "FileName";
dgvList.Columns[3].DataPropertyName = "FileVersion";
dgvList.Columns[5].DataPropertyName = "FileSize";
dgvList.Columns[6].DataPropertyName = "FileDate";
dgvList.Columns[7].DataPropertyName = "FilesHash";
dgvList.Columns[8].DataPropertyName = "FilesMD5";
dgvList.Columns[9].DataPropertyName = "FilePath";
dgvList.Columns[10].DataPropertyName = "FileType";
dgvList.Columns[11].DataPropertyName = "UpdateBit";
dgvList.Columns[12].DataPropertyName = "RegBit";
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
// Application.ExitThread();
// Application.Exit();
}
private void DataCheck()
{
//检查是否更新文件
if (dgvList.Rows.Count != 0)
{
for (int i = 0; i < dgvList.Rows.Count; i++)
{
string fileName = "";
string strg = "";
fileName = dgvList.Rows[i].Cells[2].Value.ToString();
strg = Application.StartupPath.ToString();//得到应用程序路径信息
if (dgvList.Rows[i].Cells[9].Value.ToString() != "")
{
strg += "\\" + dgvList.Rows[i].Cells[9].Value.ToString();//添加路径信息
}
strg += "\\" + fileName;//添加文件名称
//检查文件是否存在
//文件版本号
// FileInfo file = new FileInfo(strg);
if (FileUtil.IsExistFile(strg))
{
if ((FileUtil.MD5File(strg).ToString()) == (dgvList.Rows[i].Cells[8].Value.ToString()))
{
dgvList.Rows[i].Cells[0].Value = false;
}
else
{
dgvList.Rows[i].Cells[0].Value = true;
}
FileVersionInfo fileVersion = FileVersionInfo.GetVersionInfo(strg);
dgvList.Rows[i].Cells[4].Value = fileVersion.FileVersion;
}
else
{
dgvList.Rows[i].Cells[0].Value = true;
dgvList.Rows[i].Cells[4].Value = "文件不存在";
}
}
}
}
private delegate void SetProgressVlue(int value);
private void SetValue(int value) //执行2次,第一次IF,第2次ELSE
{
if (this.InvokeRequired) //是否处于控件线程外
{
SetProgressVlue d = new SetProgressVlue(SetValue); //创建一个SetProgressVlue的委托实例d,并将SetVlue赋值
object arg = value; //给参数的值
this.Invoke(d, arg); //将该值传递给D
}
else
{
this.pbDownFile.Value += value;
}
}
private void btnNext_Click(object sender, EventArgs e)
{
if (dgvList.Rows.Count == 0)
{
MessageBox.Show("没有可用的更新!", "自动更新", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
for (int i = 0; i < dgvList.Rows.Count; i++)
{
if (dgvList.Rows[i].Cells[0].Value == null) //第一次都是null
{
dgvList.Rows[i].Cells[0].Value = false;
}
if ((dgvList.Rows[i].Cells[0].Value.ToString()) == "True")
{
isUpdate = true;
}
}
if (isUpdate==false)
{
MessageBox.Show("没有可用的更新!", "自动更新", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
this.pbDownFile.Value = 0;
string strSQL41 = "SELECT * FROM SysUpdate where UpdateBit=1 order by ID;";
DataSet ds = W1.DS(strSQL41,"Sys");
//检查目录对应文件MD5是否一样,
//如果一样表示已经更新无需更新
if (ds.Tables[0].Rows.Count >= 1)
{
pbDownFile.Maximum = ds.Tables[0].Rows.Count;
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
SetValue(1);
string fileName = "";
string strg = "";
fileName = ds.Tables[0].Rows[i]["FileName"].ToString();
strg = Application.StartupPath.ToString();//得到应用程序路径信息
if (ds.Tables[0].Rows[i]["FilePath"].ToString() != "")
{
strg += "\\" + ds.Tables[0].Rows[i]["FilePath"].ToString();//添加路径信息
}
strg += "\\" + fileName;//添加文件名称
//检查文件是否存在
if (FileUtil.IsExistFile(strg))
{
if ((FileUtil.MD5File(strg).ToString()) == (ds.Tables[0].Rows[i]["FilesMD5"].ToString()))
{
}
else
{
CloseMainExe();
//删除当前文件
FileUtil.DeleteFile(strg);
byte[] MyData2 = new byte[0];
MyData2 = (byte[])ds.Tables[0].Rows[i]["FileData"];
byte[] args0 = Common.SharpZip.ICGzipDecompress(MyData2);//解压
//MemoryStream mystream = new MemoryStream(Common.SharpZip.DecompressB(MyData2));//解压
FileStream fs = new FileStream(strg, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
fs.Write(args0, 0, args0.Length);
fs.Close();
//是否注册
if (ds.Tables[0].Rows[i]["RegBit"].ToString() == "True")
{
Process p = new Process();
p.StartInfo.FileName = "Regsvr32.exe";
p.StartInfo.Arguments = "/s " + strg;//
}
}
}
else
{
string DirectoryStrg = Application.StartupPath.ToString();//得到应用程序路径信息
if (ds.Tables[0].Rows[i]["FilePath"].ToString() != "")
{
DirectoryStrg += "\\" + ds.Tables[0].Rows[i]["FilePath"].ToString();//添加路径信息
}
if (DirectoryUtil.IsExistDirectory(DirectoryStrg))
{
}
else
{
DirectoryUtil.CreateDirectory(DirectoryStrg);
}
byte[] MyData2 = new byte[0];
MyData2 = (byte[])ds.Tables[0].Rows[i]["FileData"];
byte[] args0 = Common.SharpZip.ICGzipDecompress(MyData2);
// MemoryStream mystream = new MemoryStream(Common.SharpZip.DecompressB(MyData2));//解压
FileStream fs = new FileStream(strg, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
fs.Write(args0, 0, args0.Length);
fs.Close();
if (ds.Tables[0].Rows[i]["RegBit"].ToString() == "True")
{
Process p = new Process();
p.StartInfo.FileName = "Regsvr32.exe";
p.StartInfo.Arguments = "/s " + strg;//
}
}
}
DataCheck();
panel2.Location = panel1.Location;
panel2.Size = panel1.Size;
panel1.Visible = false;
panel2.Visible = true;
btnNext.Visible = false;
StarMainExe();
Application.Exit();
}
}
private void CloseMainExe()
{
try
{
string localXmlFile = Application.StartupPath + "\\UpdateList.xml";
isRun = W1.LoadXmlFileValue("UpdateList.xml", "Application", "AllowStart").ToLower() == "true" ? true : isRun;
mainAppExe = W1.LoadXmlFileValue("UpdateList.xml", "Application", "AppName");
Process[] processesByName = Process.GetProcessesByName(mainAppExe.Replace(".exe", ""));
for (int i = 0; i < processesByName.Length; i++)
{
Process p = processesByName[i];
for (int j = 0; j < p.Threads.Count; j++)
{
p.Threads[j].Dispose();
}
p.Kill();
if (i == processesByName.Length - 1) Thread.Sleep(550);
}
}
catch
{
MessageBox.Show("关闭运行中的进程发生错误,请联系管理员!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//finally
//{
// this.Close();
// this.Dispose();
// // Application.ExitThread();
// // Application.Exit();
//}
}
private void StarMainExe()
{
try
{
string localXmlFile = Application.StartupPath + "\\UpdateList.xml";
isRun = false;
mainAppExe = W1.LoadXmlFileValue("UpdateList.xml", "Application", "AppName");
Process[] processesByName = Process.GetProcessesByName(mainAppExe.Replace(".exe", ""));
for (int i = 0; i < processesByName.Length; i++)
{
if (processesByName[i].ToString().ToLower() == mainAppExe.ToString().ToLower())
{
isRun = true;
break;
}
}
if (false == this.isRun) Process.Start(mainAppExe);
}
catch
{
MessageBox.Show("重启主程序发生错误,请联系管理员!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
this.Close();
this.Dispose();
// Application.ExitThread();
// Application.Exit();
}
}
private void dgvList_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
for (int i = 0; i < this.dgvList.Rows.Count; )
{
this.dgvList.Rows[i].DefaultCellStyle.BackColor = System.Drawing.Color.FromArgb(Convert.ToInt32(W1.LoadXmlFileValue("config.xml", "Color", "IMColor"))); ;// pParentWin.globalcolor2;
i += 2;
}
}
private void btnRefresh_Click(object sender, EventArgs e)
{
string strSQL41 = "SELECT * FROM SysUpdate order by ID ;";
DataSet ds = W1.DS(strSQL41,"Sys");
dgvList.DataSource = ds.Tables[0].DefaultView;
this.DataBinding();
DataCheck();
}
private SysUpdate.frmSysUpdateUp frmsysupdateup = null;
private void OpenUpload()
{
if (FindFormName("frmSysUpdateUp") == null)
{
frmsysupdateup = new SysUpdate.frmSysUpdateUp(); ;
frmsysupdateup.Show();
frmsysupdateup.Focus();
}
else
{
Form f = FindFormName("frmSysUpdateUp") as Form;
f.Focus();
}
}
/// <summary>在OpenForms中查找已经打开的窗口 </summary>
/// <param name="text">传入的窗口名称</param>
/// <returns>返回的窗口</returns>
private Form FindFormName(string name)
{
foreach (Form form in Application.OpenForms)
//窗口名称
if (form.Name == name)
return form;
return null;
}
private void frmLocalUpdate_KeyPress(object sender, KeyPressEventArgs e)
{
if ((Control.ModifierKeys & Keys.Control) == Keys.Control && e.KeyChar==19)
{
OpenUpload();
}
}
//protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
//{
// if ((keyData & Keys.Alt) == Keys.Alt)//检测到alt
// {
// if ((keyData & Keys.Control) == Keys.Control)
// {
// System.Windows.Forms.SendKeys.Send("^%");
// return true;
// }
// }
// return base.ProcessCmdKey(ref msg, keyData);
//}
}
}
5) 通过webservice在线更新功能代码:
namespace SysUpdate
{
public partial class frmOnlineUpdate : Form
{
private string updateUrl = string.Empty;
private string tempUpdatePath = string.Empty;
WinBase.Common W1 = new WinBase.Common();
DataSet ds1 = new DataSet();
bool isRun = false;
bool isUpdate = false;
string mainAppExe = "";
public frmOnlineUpdate()
{
InitializeComponent();
}
private void frmOnlineUpdate_Load(object sender, EventArgs e)
{
//数据库SysUpdate表 显示需要更新内容
dgvList.ColumnCount = 10;
dgvList.AutoGenerateColumns = false;
DataGridViewCheckBoxColumn newColumn = new DataGridViewCheckBoxColumn();
DataGridViewCheckBoxColumn newColumn1 = new DataGridViewCheckBoxColumn();
DataGridViewCheckBoxColumn newColumn2 = new DataGridViewCheckBoxColumn();
dgvList.Columns.Insert(0, newColumn);
dgvList.Columns.Insert(11, newColumn1);
dgvList.Columns.Insert(12, newColumn2);
this.SetdgvListHeadText();
string localXmlFile = Application.StartupPath + "\\UpdateList.xml";
txtAddress.Text = W1.LoadXmlFileValue("UpdateList.xml", "Updater", "Url");
Down();
dgvList.DataSource = ds1.Tables[0].DefaultView;
this.DataBinding();
dgvList.Columns[0].Frozen = true;
dgvList.Columns[1].Frozen = true;
dgvList.Columns[2].Frozen = true;
dgvList.Columns[3].Frozen = true;
// dgvList.Columns[4].Frozen = true;
DataCheck();
}
private void Down()
{
string url = txtAddress.Text;
#region 从服务器获取更新列表
object result = WebServicesHelper.InvokeWebService(url, "GetUpdateFile", null);
byte[] tb = (byte[])result;
object[] ob = Common.SharpZip.DecompressNew(tb);
DataTable[] tb2 = (DataTable[])ob;
for (int i = 0; i < tb2.Length; i++)
{
ds1.Tables.Add(tb2[i]);
}
#endregion
}
private void SetdgvListHeadText()
{
dgvList.Columns[0].HeaderText = "选择";
dgvList.Columns[0].Width = 50;
dgvList.Columns[1].HeaderText = "ID";
dgvList.Columns[1].Width = 20;
dgvList.Columns[1].ReadOnly = true;
dgvList.Columns[2].HeaderText = "组件名";
dgvList.Columns[2].Width = 120;
dgvList.Columns[2].ReadOnly = true;
dgvList.Columns[3].HeaderText = "服务器版本号";
dgvList.Columns[3].Width = 120;
dgvList.Columns[3].ReadOnly = true;
dgvList.Columns[4].HeaderText = "本地版本号";
dgvList.Columns[4].Width = 120;
dgvList.Columns[4].ReadOnly = true;
dgvList.Columns[5].HeaderText = "大小";
dgvList.Columns[5].Width = 100;
dgvList.Columns[5].ReadOnly = true;
dgvList.Columns[6].HeaderText = "创建日期";
dgvList.Columns[6].Width = 150;
dgvList.Columns[6].ReadOnly = true;
dgvList.Columns[7].HeaderText = "哈希值";
dgvList.Columns[7].Width = 250;
dgvList.Columns[7].ReadOnly = true;
dgvList.Columns[8].HeaderText = "MD5值";
dgvList.Columns[8].Width = 250;
dgvList.Columns[8].ReadOnly = true;
dgvList.Columns[9].HeaderText = "目录";
dgvList.Columns[9].Width = 80;
dgvList.Columns[9].ReadOnly = true;
dgvList.Columns[10].HeaderText = "文件类型";
dgvList.Columns[10].Width = 80;
dgvList.Columns[10].ReadOnly = true;
dgvList.Columns[11].HeaderText = "是否更新";
dgvList.Columns[11].Width = 80;
// dgvList.Columns[10].ReadOnly = true;
dgvList.Columns[12].HeaderText = "是否需要注册";
dgvList.Columns[12].Width = 110;
//dgvList.Columns[11].ReadOnly = true;
}
private void DataBinding()
{
// ID, FileName, FileVersion, FilePath, FileData, FileSize, FileDate, FileType, FilesHash, FilesMD5, UpdateBit, RegBit
dgvList.Columns[0].DataPropertyName = "Check1";
dgvList.Columns[1].DataPropertyName = "ID";
dgvList.Columns[2].DataPropertyName = "FileName";
dgvList.Columns[3].DataPropertyName = "FileVersion";
dgvList.Columns[5].DataPropertyName = "FileSize";
dgvList.Columns[6].DataPropertyName = "FileDate";
dgvList.Columns[7].DataPropertyName = "FilesHash";
dgvList.Columns[8].DataPropertyName = "FilesMD5";
dgvList.Columns[9].DataPropertyName = "FilePath";
dgvList.Columns[10].DataPropertyName = "FileType";
dgvList.Columns[11].DataPropertyName = "UpdateBit";
dgvList.Columns[12].DataPropertyName = "RegBit";
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
// Application.ExitThread();
// Application.Exit();
}
private void DataCheck()
{
//检查是否更新文件
if (dgvList.Rows.Count != 0)
{
for (int i = 0; i < dgvList.Rows.Count; i++)
{
string fileName = "";
string strg = "";
fileName = dgvList.Rows[i].Cells[2].Value.ToString();
strg = Application.StartupPath.ToString();//得到应用程序路径信息
if (dgvList.Rows[i].Cells[9].Value.ToString() != "")
{
strg += "\\" + dgvList.Rows[i].Cells[9].Value.ToString();//添加路径信息
}
strg += "\\" + fileName;//添加文件名称
//检查文件是否存在
//文件版本号
// FileInfo file = new FileInfo(strg);
if (FileUtil.IsExistFile(strg))
{
if ((FileUtil.MD5File(strg).ToString()) == (dgvList.Rows[i].Cells[8].Value.ToString()))
{
dgvList.Rows[i].Cells[0].Value = false;
}
else
{
dgvList.Rows[i].Cells[0].Value = true;
}
FileVersionInfo fileVersion = FileVersionInfo.GetVersionInfo(strg);
dgvList.Rows[i].Cells[4].Value = fileVersion.FileVersion;
}
else
{
dgvList.Rows[i].Cells[0].Value = true;
dgvList.Rows[i].Cells[4].Value = "文件不存在";
}
}
}
}
private delegate void SetProgressVlue(int value);
private void SetValue(int value) //执行2次,第一次IF,第2次ELSE
{
if (this.InvokeRequired) //是否处于控件线程外
{
SetProgressVlue d = new SetProgressVlue(SetValue); //创建一个SetProgressVlue的委托实例d,并将SetVlue赋值
object arg = value; //给参数的值
this.Invoke(d, arg); //将该值传递给D
}
else
{
this.pbDownFile.Value += value;
}
}
private void btnNext_Click(object sender, EventArgs e)
{
if (dgvList.Rows.Count == 0)
{
MessageBox.Show("没有可用的更新!", "自动更新", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
for (int i = 0; i < dgvList.Rows.Count; i++)
{
if (dgvList.Rows[i].Cells[0].Value == null) //第一次都是null
{
dgvList.Rows[i].Cells[0].Value = false;
}
if ((dgvList.Rows[i].Cells[0].Value.ToString()) == "True")
{
isUpdate = true;
}
}
if (isUpdate==false)
{
MessageBox.Show("没有可用的更新!", "自动更新", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
this.pbDownFile.Value = 0;
string strSQL41 = "SELECT * FROM SysUpdate where UpdateBit=1 order by ID;";
DataSet ds = W1.DS(strSQL41,"Sys");
//检查目录对应文件MD5是否一样,
//如果一样表示已经更新无需更新
if (ds.Tables[0].Rows.Count >= 1)
{
pbDownFile.Maximum = ds.Tables[0].Rows.Count;
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
SetValue(1);
string fileName = "";
string strg = "";
fileName = ds.Tables[0].Rows[i]["FileName"].ToString();
strg = Application.StartupPath.ToString();//得到应用程序路径信息
if (ds.Tables[0].Rows[i]["FilePath"].ToString() != "")
{
strg += "\\" + ds.Tables[0].Rows[i]["FilePath"].ToString();//添加路径信息
}
strg += "\\" + fileName;//添加文件名称
//检查文件是否存在
if (FileUtil.IsExistFile(strg))
{
if ((FileUtil.MD5File(strg).ToString()) == (ds.Tables[0].Rows[i]["FilesMD5"].ToString()))
{
}
else
{
CloseMainExe();
//删除当前文件
FileUtil.DeleteFile(strg);
byte[] MyData2 = new byte[0];
MyData2 = (byte[])ds.Tables[0].Rows[i]["FileData"];
byte[] args0 = Common.SharpZip.DecompressB(MyData2);//解压
//MemoryStream mystream = new MemoryStream(Common.SharpZip.DecompressB(MyData2));//解压
FileStream fs = new FileStream(strg, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
fs.Write(args0, 0, args0.Length);
fs.Close();
//是否注册
if (ds.Tables[0].Rows[i]["RegBit"].ToString() == "True")
{
Process p = new Process();
p.StartInfo.FileName = "Regsvr32.exe";
p.StartInfo.Arguments = "/s " + strg;//
}
}
}
else
{
string DirectoryStrg = Application.StartupPath.ToString();//得到应用程序路径信息
if (ds.Tables[0].Rows[i]["FilePath"].ToString() != "")
{
DirectoryStrg += "\\" + ds.Tables[0].Rows[i]["FilePath"].ToString();//添加路径信息
}
if (DirectoryUtil.IsExistDirectory(DirectoryStrg))
{
}
else
{
DirectoryUtil.CreateDirectory(DirectoryStrg);
}
byte[] MyData2 = new byte[0];
MyData2 = (byte[])ds.Tables[0].Rows[i]["FileData"];
byte[] args0 = Common.SharpZip.ICGzipDecompress(MyData2);
// MemoryStream mystream = new MemoryStream(Common.SharpZip.DecompressB(MyData2));//解压
FileStream fs = new FileStream(strg, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
fs.Write(args0, 0, args0.Length);
fs.Close();
if (ds.Tables[0].Rows[i]["RegBit"].ToString() == "True")
{
Process p = new Process();
p.StartInfo.FileName = "Regsvr32.exe";
p.StartInfo.Arguments = "/s " + strg;//
}
}
}
DataCheck();
panel2.Location = panel1.Location;
panel2.Size = panel1.Size;
panel1.Visible = false;
panel2.Visible = true;
btnNext.Visible = false;
StarMainExe();
Application.Exit();
}
}
private void CloseMainExe()
{
try
{
string localXmlFile = Application.StartupPath + "\\UpdateList.xml";
isRun = W1.LoadXmlFileValue("UpdateList.xml", "Application", "AllowStart").ToLower() == "true" ? true : isRun;
mainAppExe = W1.LoadXmlFileValue("UpdateList.xml", "Application", "AppName");
Process[] processesByName = Process.GetProcessesByName(mainAppExe.Replace(".exe", ""));
for (int i = 0; i < processesByName.Length; i++)
{
Process p = processesByName[i];
for (int j = 0; j < p.Threads.Count; j++)
{
p.Threads[j].Dispose();
}
p.Kill();
if (i == processesByName.Length - 1) Thread.Sleep(550);
}
}
catch
{
MessageBox.Show("关闭运行中的进程发生错误,请联系管理员!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//finally
//{
// this.Close();
// this.Dispose();
// // Application.ExitThread();
// // Application.Exit();
//}
}
private void StarMainExe()
{
try
{
string localXmlFile = Application.StartupPath + "\\UpdateList.xml";
isRun = false;
mainAppExe = W1.LoadXmlFileValue("UpdateList.xml", "Application", "AppName");
Process[] processesByName = Process.GetProcessesByName(mainAppExe.Replace(".exe", ""));
for (int i = 0; i < processesByName.Length; i++)
{
if (processesByName[i].ToString().ToLower() == mainAppExe.ToString().ToLower())
{
isRun = true;
break;
}
}
if (true == this.isRun) Process.Start(mainAppExe);
}
catch
{
MessageBox.Show("重启主程序发生错误,请联系管理员!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
this.Close();
this.Dispose();
// Application.ExitThread();
// Application.Exit();
}
}
private void dgvList_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
for (int i = 0; i < this.dgvList.Rows.Count; )
{
this.dgvList.Rows[i].DefaultCellStyle.BackColor = System.Drawing.Color.FromArgb(Convert.ToInt32(W1.LoadXmlFileValue("config.xml", "Color", "IMColor"))); ;// pParentWin.globalcolor2;//System.Drawing.Color.FromArgb(Convert.ToInt32(-2302756));//
i += 2;
}
}
private void btnRefresh_Click(object sender, EventArgs e)
{
Down();
dgvList.DataSource = ds1.Tables[0].DefaultView;
this.DataBinding();
DataCheck();
}
}
}
6) 软件商webserice代码
namespace HostWebService
{
/// <summary>
/// Summary description for Service1
/// </summary>
// [WebService(Namespace = "http://tempuri.org/")]
[WebService(Namespace = "http://localhost/sysupdate/SysUpdate.asmx/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class HostService : System.Web.Services.WebService
{
WebBase W1 = new WebBase();
#region WebService Get Method
[WebMethod(Description = "取得服务器上的相关更新资料DataSet")]
public byte[] GetUpdateFile()
{
string strSQL = "SELECT * FROM SysUpdate where UpdateBit=1 order by ID;";
DataSet ds = W1.DS(strSQL, "Sys");
DataTable[] tb = new DataTable[ds.Tables.Count];
for (int i = 0; i < ds.Tables.Count; i++)
{
tb[i] = ds.Tables[i];
}
return Common.SharpZip.Compress(tb);
}
#endregion
#region WebService Post Method
[WebMethod(Description = "更新相关文件")]
public int UploadUpdateFile(byte[] result)
{
int id = 0;
byte[] tb = (byte[])result;
object[] ob = Common.SharpZip.DecompressNew(tb);
DataTable[] tb2 = (DataTable[])ob;
DataSet ds1 = new DataSet();
for (int i = 0; i < tb2.Length; i++)
{
ds1.Tables.Add(tb2[i]);
}
if (ds1.Tables[0].Rows.Count > 0)
{
for (int i = 0; i < ds1.Tables[0].Rows.Count; i++)
{
string strSQL = "select * from SysUpdate where ID=‘" + ds1.Tables[0].Rows[i][0].ToString() + "‘";
DataSet ds10 = W1.DS(strSQL, "Sys");
if (ds10.Tables[0].Rows.Count > 0) //记录已存在时
{
strSQL = "Delete from SysUpdate where ID=‘" + ds1.Tables[0].Rows[i][0].ToString() + "‘; Insert into SysUpdate values(";
for (int j = 0; j < ds1.Tables[0].Columns.Count - 1; j++)
{
if (ds1.Tables[0].Columns[j].DataType.ToString() == "System.Double" || ds1.Tables[0].Columns[j].DataType.ToString() == "System.Decimal") //Double型的要特别处理,不能看成字符型
{
if (ds1.Tables[0].Rows[i][j].ToString() == "")
{
strSQL += "null" + ",";
}
else
{
strSQL += ds1.Tables[0].Rows[i][j].ToString() + ",";
}
}
else
{
strSQL += "‘" + ds1.Tables[0].Rows[i][j].ToString() + "‘,";
}
}
strSQL += "‘" + ds1.Tables[0].Rows[i][ds1.Tables[0].Columns.Count - 1].ToString() + "‘)";
try
{
W1.DC(strSQL, "Sys");
id++;
}
catch
{
return id = -1;
}
}
else
{
strSQL = " Insert into SysUpdate values(";
for (int j = 0; j < ds1.Tables[0].Columns.Count - 1; j++)
{
if (ds1.Tables[0].Columns[j].DataType.ToString() == "System.Double" || ds1.Tables[0].Columns[j].DataType.ToString() == "System.Decimal") //Double型的要特别处理,不能看成字符型
{
if (ds1.Tables[0].Rows[i][j].ToString() == "")
{
strSQL += "null" + ",";
}
else
{
strSQL += ds1.Tables[0].Rows[i][j].ToString() + ",";
}
}
else
{
strSQL += "‘" + ds1.Tables[0].Rows[i][j].ToString() + "‘,";
}
}
strSQL += "‘" + ds1.Tables[0].Rows[i][ds1.Tables[0].Columns.Count - 1].ToString() + "‘)";
try
{
W1.DC(strSQL, "Sys");
id++;
}
catch
{
return id = -1;
}
}
}
}
return id;
}
#endregion
private void InitializeComponent()
{
}
}
}
7) 更新配置文件:UpdateList.xml
<?xml version="1.0" encoding="gb2312"?>
<Configs>
<Updater>
<Url>http://218.X.X.2/sysupdate/HostService.asmx</Url> //升级文件所在服务器端的网址
</Updater>
<Application>
<AllowStart>true</AllowStart> //允许重新启动应用程序
<AppName>ECM.exe</AppName> //启动的应用程序名
</Application>
</Configs>
8) ECM系统Login时检查是否有更新档功能代码:
private void CheckUpdate()
{
string strSQL41 = "SELECT * FROM SysUpdate where UpdateBit=1 order by ID;";
DataSet ds = W1.DS(strSQL41,"Sys");
//检查目录对应文件MD5是否一样,
//如果一样表示已经更新无需更新
if (ds.Tables[0].Rows.Count >= 1)
{
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
string fileName = "";
string strg = "";
fileName = ds.Tables[0].Rows[i]["FileName"].ToString();
strg = Application.StartupPath.ToString();//得到应用程序路径信息
if (ds.Tables[0].Rows[i]["FilePath"].ToString() != "")
{
strg += "\\" + ds.Tables[0].Rows[i]["FilePath"].ToString();//添加路径信息
}
strg += "\\" + fileName;//添加文件名称
//检查文件是否存在
if (SysUpdate.FileUtil.IsExistFile(strg))
{
if ((SysUpdate.FileUtil.MD5File(strg).ToString()) == (ds.Tables[0].Rows[i]["FilesMD5"].ToString()))
{
}
else
{
isUpdate = true;
}
}
else
{
isUpdate = true;
}
}
}
if (isUpdate)
{
if (MessageBox.Show("服务器存在更新版本,是否更新为最新版", "系统提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
System.Diagnostics.Process.Start("SysUpdate.exe");
}
}
}
5、 有关更多的技术分享,大家可以加入我们的技术群,进行源码的分享。
欢迎加入技术分享群:238916811