一個軟體在做調整以後,都是要更新更新的,如果這個時候要求使用者重新去下載下傳,體驗非常不好,是以程式一運作起來,就應該判斷是不是要更新,如果要的話,直接自動更新,再運作,這樣使用者體驗會好很多。
任務過程:更新的檔案是放在一個遠端目錄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";
有一天你想在下載下傳清單中新加一些檔案,如果你這樣寫就得重新改程式,我用的方法是浏覽更新檔案目錄,把目錄下所有檔案名讀出來,這樣你下次要求軟體更新時,新增檔案直接複制到遠端目錄中就可以了。
這個功能前幾天我寫過,有要用的可以點下面去看:
C#得到遠端目錄中的檔案名稱