网站首页 > 技术文章 正文
一个软件在做调整以后,都是要升级更新的,如果这个时候要求用户重新去下载,体验非常不好,所以程序一运行起来,就应该判断是不是要更新,如果要的话,直接自动更新,再运行,这样用户体验会好很多。
任务过程:更新的文件是放在一个远程目录http://192.168.1.100/Resourse/Update/中,软件启动后,先判断是不是需要更新,如果要,去远程目录下载文件更新,然后再运行,中间需要用户看到下载更新的过程
效果如图:这里我只是实现的过程,细节比如文字啥的比较简单,就没有弄
1、创建一个名为Update的项目,窗体名称改为DownFileFromURL,窗体代码如下:(大多数函数我已经弄好,直接复制就可以,注释的地方看下应该不难)
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows.Forms;
namespace Update
{
public partial class DownFileFromURL : Form
{
string webURL; //远程下载文件地址
string[] FileNames; //要下载的文件名数组
//下载的文件是否加上tmp,这个是我当时做别的加的功能,这里没什么用
string ReName;
//更新成功后,运行哪个文件
string RunEXEname;
//完成成功标志,初始值为false
bool ok = false;
//构造函数
public DownFileFromURL(string theurl, string filenames, string renametoaddtmp,string runwho)
{
#region 调用示例
//string filenames = "a.exe|b.txt|c.bmp";
//string args = "";
////下载地址
//string args += "http://192.168.1.100/Resourse/Update/ ";
////下载文件名字符串,用“|”隔开
//args += filenames + " ";
////更新文件不改名
//args += "false" + " ";
////更新结束后运行哪个文件
//args += "\\a.exe" + " ";
#endregion
//初始化本地参数
webURL = theurl;
FileNames = filenames.Split('|');
ReName = renametoaddtmp;
RunEXEname = runwho;
InitializeComponent();
}
private void DownFileFromURL_Load(object sender, EventArgs e)
{
//在线程中操作控件值的话要加上下面这句话
CheckForIllegalCrossThreadCalls = false;
label1.Text = "开始下载新版本,请稍等...";
Thread t = new Thread(new ThreadStart(DownFileGo));
t.Start();
}
void DownFileGo()
{
int howmanyfiles = FileNames.Length;
for (int i = 0; i < howmanyfiles; i++)
{
//逐个下载
DownFile(mybar, Application.StartupPath + "\\", webURL + "/" + FileNames[i], ReName);
if (i == howmanyfiles - 1)
{
//下载完以后如果参数中要求直接运行指定程序,就运行它
if (RunEXEname.Length != 0)
{
Process.Start(Application.StartupPath + RunEXEname);
}
//成功标志改为true
ok = true;
this.Close();
break;
}
}
}
private void DownFile(ProgressBar thebar, string dir, string URL, string rename)
{
string filename = URL.Substring(URL.LastIndexOf("/") + 1);
string FileName = dir + filename; //下载到其它目录下,dir参数未测试
if (rename == "true") { FileName = FileName + ".tmp"; }
//得到远程文件信息
HttpWebRequest Myrq = (HttpWebRequest)HttpWebRequest.Create(URL);
HttpWebResponse myrp = (HttpWebResponse)Myrq.GetResponse();
long totalBytes = myrp.ContentLength;
thebar.Maximum = (int)totalBytes;
//常规文件流处理代码
Stream st = myrp.GetResponseStream();
Stream so = new FileStream(FileName.Replace("%20", " ").Replace("%2520", " "), FileMode.Create);
long totalDownloadedByte = 0;
byte[] by = new byte[1024];
int osize = st.Read(by, 0, (int)by.Length);
while (osize > 0)
{
totalDownloadedByte = osize + totalDownloadedByte;
Application.DoEvents();
so.Write(by, 0, osize);
thebar.Value = (int)totalDownloadedByte;
osize = st.Read(by, 0, (int)by.Length);
if (thebar.Value == (int)totalBytes)
{
thebar.Value = 0;
}
}
so.Close();
st.Close();
}
private void DownFileFromURL_FormClosing(object sender, FormClosingEventArgs e)
{
//如果还没下载完,退出
if (!ok)
{
e.Cancel = true;
}
}
}
}
2、设置它的启动参数,修改program.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Update
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
Process instance = RunningInstance();
//这个程序是否运行,因为我自己用,所以我一直用进程名判断
if (instance == null)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//如果参数个数正确
if (args.Length == 5)
{
string theurl = args[0];
string filenames = args[1];
string rename = args[2];
string runexename = args[3];
//这里先把自己的主程序进程杀掉,
//再运行更新窗体
string killexename = args[4];
Kill(killexename);
Application.Run(new DownFileFromURL(theurl, filenames, rename, runexename));
}
else
{
MessageBox.Show("^#$#!#@!*^*@%#$#!@%\r\n\r\n@%#!@%!#@!*^@%#!@%!@%@%#$#!@%#@!*^\r\n\r\n#@!*^@%#!@%!@%#@!*^#$#@%!@%#@!*^#\r\n\r\n................");
}
}
else
{
Process.GetCurrentProcess().Kill();
}
}
/// <summary>
/// 杀死进程
/// <para>Kill("winword");不带exe</para>
/// </summary>
/// <param name="pname">进程名称,不带exe</param>
public static void Kill(string pname)
{
try
{
Process[] p = Process.GetProcesses();
foreach (Process tp in p)
{
if (tp.ProcessName == pname | tp.ProcessName.ToLower() == pname)
{
tp.Kill();
}
}
}
catch
{ }
}
public static Process RunningInstance()
{
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);
foreach (Process process in processes)
{
if (process.Id != current.Id)
{
if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName)
{
return process;
}
}
}
return null;
}
}
}
经过这两步,更新程序本身就完成了,文件名就是项目名:update.exe.现在我们来看下如何用其它程序来调用它。
新建一个主程序 ksh.exe,在它运行时,比如可以放在program.cs中,加入以下模块
//我更改了数据库中的更新版本号
//此时从库中读出来,也就是库中片版本号,当然也可以想其它办法
string cmdstr = "select Cver from Ver";
string dbver = GetFirstData(cmdstr);
//当前片版本号
//[assembly: AssemblyFileVersion("1.0")]
//这个也可以把当前版本号放在xml中与dbver对比,更新完再更新xm即可
string nowver = Application.ProductVersion;
//更新文件文件名
string exename = Application.StartupPath + "\\Update.exe";
//如果版本号不一致
if (dbverf > nowverf)
{
//添加update.exe运行需要的参数
//下载地址
string args = "http://192.168.1.100/Resourse/Update/C ";
//要下载的文件名列表
string filenames = "a.exe|b.txt|c.xml";
string[] filenamesarr = filenames.Split('|');
args += filenames + " ";
//下载的文件是否改名
args += "false" + " ";
//更新后运行哪个文件
args += "\\a.exe" + " ";
//我当前的进程名,因为要更新自己的话
//万一自己还没有退出,则需要让update.exe杀死自己
//当然你也可以让update检测,等它退出再更新
args += "ksh";
//运行update.exe
RunINCMD(exename, args);
//退出自己,准备更新
Application.ExitThread();
this.DialogResult = DialogResult.No;
}
void RunINCMD(string EXEname, string Args)
{
System.Diagnostics.Process Process1 = new System.Diagnostics.Process();
Process1.StartInfo.FileName = EXEname;
Process1.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
Process1.StartInfo.Arguments = " " + Args;
Process1.Start();
Process1.WaitForExit();
}
这样当ksh.exe运行后,就会先判断自己的版本号与远程版本号是不是一致,如果不一致,就提供update.exe需要的参数,然后运行update.exe,自己退出或被update.exe文件kill掉,保证更新进行。
在更新过程中,因为我是写在线程中的,所以有几个文件,大小多少,下载进度这些都是可控的,我没有写
最后,
//要下载的文件名列表
string filenames = "a.exe|b.txt|c.xml";
有一天你想在下载列表中新加一些文件,如果你这样写就得重新改程序,我用的方法是浏览更新文件目录,把目录下所有文件名读出来,这样你下次要求软件更新时,新增文件直接复制到远程目录中就可以了。
这个功能前几天我写过,有要用的可以点下面去看:
猜你喜欢
- 2024-10-01 Excel VBA 事件过程实现数据变化结果也会随之自动更新
- 2024-10-01 每天长时间盯着电脑,这三招帮你缓解眼睛疲劳
- 2024-10-01 Excel-VBA:13、Excel事件程序(vba事件怎么触发)
- 2024-10-01 excel vba常用语句干货分享,错过了就不会再有了(关注!)
- 2024-10-01 设计模式之观察者模式,事件机制的底层原理全面解析(建议收藏)
- 2024-10-01 相同单元格自动变色提醒(相同单元格自动变色提醒怎么取消)
- 2024-10-01 Excel实用技巧:根据条件,锁定某个单元格
- 2024-10-01 苹果电脑这些超实用的隐藏功能,不会用就等于白花钱了!
- 2024-10-01 办公小技巧:制作自动显示子菜单的下拉菜单
- 2024-10-01 常用的、带解释的 VBA 短句(vba常用语句详解)
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)