Wince后台系统补丁更新实现
2012-04-06 14:27
375 查看
虽说是在WINCE手持平台上,但是系统架构还是C/S模式没有变,C/S模式比较难搞的一个部分就是系统更新,这个在WINCE平台下处理方式跟PC平台上也无特别大的区别,思路差不多都是如下模式:
1.程序启动之前验证版本
2.如果版本不一致则下载更新
WINCE当然也是这个模式,有点不同的就是WINCE更新时候需要安装CAB包,代码下只能用WINCE自带的CAB包安装命令
ClientLoader窗体就是更新的主程序,主要逻辑都在这种实现。
AppConfiger是自己创建的CONFIG读取类,实现可在我之前的博文http://www.cnblogs.com/vinnie520/archive/2012/03/13/2393337.html 中看到。
.ico是程序图标,因为是系统入口程序,所以把这个程序加上图标而不是加在实际应用程序上。
updateHelper是创建的静态类,用于下载补丁包,获取客户端\服务器版本号,检验是否需要更新之类的功能,代码如下
以上可以看到,我们的版本使用文本文件控制,本地文件安装包中有version.ver文件,是个文本文件,其中只有一行内容就是版本号,服务器也有个类似的文件,是放在FTP服务器中,我们
使用的时候是通过HTTP下载的方式读取到其中内容,至于版本控制,可以用MSBUILD保证此版本跟客户端代码的AssemblyInfo里面的version保持一致。
这个图就是我们更新使用程序的窗体。下面2个BUTTON是测试时按钮,visiable是否的,所以就请忽略吧。
此程序所有逻辑都是在LOAD方法里面实现并完成,代码如下
所有更新思路都在以上代码。首先调用 notUpdate = UpdateHelper.IfNoNeedUpdate(); 检验是否需要更新
如果不需要更新则直接启动程序(StartApp),如果需要就先下载更新包((DownLoadPathFile()),然后进行更新(UpdateApp(patchName)),最后更新成功后修改客户端版本号
(UpdateHelper.SetClientVision(UpdateHelper.GetServerVersion());),最后启动程序。
更新程序:注意到,这里更新之前首先对2个关键文件做了file.delete方法用来检验文件是否被占用,从而实现安全更新
启动程序:
下载程序:主要逻辑是在updateHelper中的download方法实现,这里只设置一下路径问题
OK,到此,基本上更新就可以完美实现,程序的入口设置成此程序,每次只要有更新之后就增加服务器版本号文件的版本,然后把编译好的补丁包放到对应的位置,每次程序开机时就会实现自动更新。
可以想一想,以上程序只完成了程序入口处检查版本,更新版本。如果我要在程序运行中发布客户端代码,那怎么样处理才是比较好呢...
1.程序启动之前验证版本
2.如果版本不一致则下载更新
WINCE当然也是这个模式,有点不同的就是WINCE更新时候需要安装CAB包,代码下只能用WINCE自带的CAB包安装命令
ProcessStartInfo info = new ProcessStartInfo(); info.FileName = @"wceload.exe"; info.Arguments = @"/noui " + path; //info.Arguments = path; System.Diagnostics.Process process = new System.Diagnostics.Process(); process.StartInfo = info; process.Start();
wceload.exe是WINCE自带的安装命令,程序调用可以加参数控制,详情可见MSDN,这个命令有个不好的地方就是如果有DLL,或者EXE占用(线程非安全退出),它在安装的时候是不会呈现出来的,这样就有可能有客户端不完整更新, 这是个很糟糕的情况,我们要想办法避免这种情况出现。因此我们必须要新建一个project完全负责更新程序,他应该是脱离应用程序的独立程序。 项目结构如图
ClientLoader窗体就是更新的主程序,主要逻辑都在这种实现。
AppConfiger是自己创建的CONFIG读取类,实现可在我之前的博文http://www.cnblogs.com/vinnie520/archive/2012/03/13/2393337.html 中看到。
.ico是程序图标,因为是系统入口程序,所以把这个程序加上图标而不是加在实际应用程序上。
updateHelper是创建的静态类,用于下载补丁包,获取客户端\服务器版本号,检验是否需要更新之类的功能,代码如下
public static void DownloadFile(string URL, string filename, System.Windows.Forms.ProgressBar prog, System.Windows.Forms.Label label1) { Application.DoEvents(); float percent = 0; try { System.Net.HttpWebRequest Myrq = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(URL); System.Net.HttpWebResponse myrp = (System.Net.HttpWebResponse)Myrq.GetResponse(); long totalBytes = myrp.ContentLength; if (prog != null) { prog.Maximum = (int)totalBytes; } System.IO.Stream st = myrp.GetResponseStream(); System.IO.Stream so = new System.IO.FileStream(filename, System.IO.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; System.Windows.Forms.Application.DoEvents(); so.Write(by, 0, osize); if (prog != null) { prog.Value = (int)totalDownloadedByte; } osize = st.Read(by, 0, (int)by.Length); percent = (float)totalDownloadedByte / (float)totalBytes * 100; label1.Text = "当前补丁下载进度" + percent.ToString() + "%"; System.Windows.Forms.Application.DoEvents(); //必须加注这句代码,否则label1将因为循环执行太快而来不及显示信息 } so.Close(); st.Close(); } catch (System.Exception) { throw; } } public static string GetServerVersion() { string result; try { var url = AppConfiger.GetAppSettingValue("VersionUrl"); System.Net.HttpWebRequest Myrq = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(url); System.Net.HttpWebResponse myrp = (System.Net.HttpWebResponse)Myrq.GetResponse(); System.IO.Stream st = myrp.GetResponseStream(); byte[] by = new byte[1024]; StreamReader m_streamReader = new StreamReader(st); result = m_streamReader.ReadLine(); m_streamReader.Close(); st.Close(); } catch (System.Exception) { throw; } return result; } public static bool IfNoNeedUpdate() { var clientVersion = GetClientVision(); var serverVersion = GetServerVersion(); var clVersion = clientVersion.Split('.'); var svVersion = serverVersion.Split('.'); for (int i = 0; i < clVersion.Count(); i++) { if (clVersion[i] != svVersion[i]) return false; } return true; // return clientVersion >= serverVersion; } private static string GetClientVision() { try { string res = ""; string appDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase); var path = Path.Combine(appDir, "version.ver"); StreamReader sr = new StreamReader(path, System.Text.Encoding.Default); while (sr.Peek() >= 0) { res = sr.ReadLine(); } sr.Close(); return res; } catch { return ""; } } public static void SetClientVision(string vision) { try { string appDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase); var path = Path.Combine(appDir, "version.ver"); StreamWriter m_streamWriter = new StreamWriter(path); m_streamWriter.Flush(); // 使用StreamWriter来往文件中写入内容 m_streamWriter.BaseStream.Seek(0, SeekOrigin.Begin); // 把richTextBox1中的内容写入文件 m_streamWriter.Write(vision); //关闭此文件 m_streamWriter.Flush(); m_streamWriter.Close(); }catch { } }
以上可以看到,我们的版本使用文本文件控制,本地文件安装包中有version.ver文件,是个文本文件,其中只有一行内容就是版本号,服务器也有个类似的文件,是放在FTP服务器中,我们
使用的时候是通过HTTP下载的方式读取到其中内容,至于版本控制,可以用MSBUILD保证此版本跟客户端代码的AssemblyInfo里面的version保持一致。
这个图就是我们更新使用程序的窗体。下面2个BUTTON是测试时按钮,visiable是否的,所以就请忽略吧。
此程序所有逻辑都是在LOAD方法里面实现并完成,代码如下
private void Form1_Load(object sender, EventArgs e) { lableTitle.Text = "程序正在启动..."; this.Show(); Application.DoEvents(); bool notUpdate = false; try { notUpdate = UpdateHelper.IfNoNeedUpdate(); } catch (Exception) { MessageBox.Show("程序启动失败,请检查网络连接"); Application.Exit(); return; } if (notUpdate) { StartApp(); // 没有更新包 } else { lableTitle.Text = "正在安装更新包..."; Application.DoEvents(); if (DownLoadPathFile()) { string patchName = GetPatchFile(); if (!UpdateApp(patchName)) { MessageBox.Show("更新失败,请重启后重新更新系统"); CloseMainForm(); } UpdateHelper.SetClientVision(UpdateHelper.GetServerVersion()); Application.DoEvents(); StartApp(); } else { StartApp(); } } }
所有更新思路都在以上代码。首先调用 notUpdate = UpdateHelper.IfNoNeedUpdate(); 检验是否需要更新
如果不需要更新则直接启动程序(StartApp),如果需要就先下载更新包((DownLoadPathFile()),然后进行更新(UpdateApp(patchName)),最后更新成功后修改客户端版本号
(UpdateHelper.SetClientVision(UpdateHelper.GetServerVersion());),最后启动程序。
更新程序:注意到,这里更新之前首先对2个关键文件做了file.delete方法用来检验文件是否被占用,从而实现安全更新
private bool UpdateApp(string path) { try { string exePath =// " \\ResidentFlash\\DeviceClient\\CP.Device.exe"; Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase), "CP.Device.exe"); string dllPath =// " \\ResidentFlash\\DeviceClient\\CP.Device.exe"; Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase), "CP.Device.Service.dll"); //更新之前删除EXE文件检查该文件是否被占用 if (File.Exists(dllPath)) File.Delete(dllPath); if (File.Exists(exePath)) File.Delete(exePath); ProcessStartInfo info = new ProcessStartInfo(); info.FileName = @"wceload.exe"; info.Arguments = @"/noui " + path; //info.Arguments = path; System.Diagnostics.Process process = new System.Diagnostics.Process(); process.StartInfo = info; process.Start(); process.WaitForExit(); return true; } catch (Exception ex) { MessageBox.Show(ex.Message); return false; } }
启动程序:
private void StartApp() { try { //先写死路径 string path =// "\\ResidentFlash\\DeviceClient\\CP.Device.exe"; Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase), AppName); if (File.Exists(path)) { Process process = new Process(); ProcessStartInfo info = new ProcessStartInfo(); info.FileName = path; process.StartInfo = info; process.Start(); CloseMainForm(); } else { MessageBox.Show("没有找到主程序'" + AppName + "'!请重新安装程序!"); Application.DoEvents(); CloseMainForm(); } } catch (Exception ex) { MessageBox.Show(ex.Message); Application.DoEvents(); CloseMainForm(); } }
下载程序:主要逻辑是在updateHelper中的download方法实现,这里只设置一下路径问题
private bool DownLoadPathFile() { string cabPath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase), "Update"); if (!Directory.Exists(cabPath)) { Directory.CreateDirectory(cabPath); } string cabFile = Path.Combine(cabPath, "patch.cab"); var patchUrl = AppConfiger.GetAppSettingValue("PatchUrl"); UpdateHelper.DownloadFile(patchUrl, cabFile, progressBar1, labeProcess); return true; }
OK,到此,基本上更新就可以完美实现,程序的入口设置成此程序,每次只要有更新之后就增加服务器版本号文件的版本,然后把编译好的补丁包放到对应的位置,每次程序开机时就会实现自动更新。
可以想一想,以上程序只完成了程序入口处检查版本,更新版本。如果我要在程序运行中发布客户端代码,那怎么样处理才是比较好呢...
相关文章推荐
- CoreLocation 的基本使用 以及定位 指南针的实现 (附加: 系统版本适配的方法,和后台更新用户位置的方法及注意)
- wince系统运行中如何实现更新flash中的NK.BIN?持续探讨,欢迎关注
- java后台系统实现动态新闻列表实时更新
- ANDROID_MARS学习笔记_S01原始版_023_MP3PLAYER005_用广播BroacastReciever实现后台播放不更新歌词
- 实战:Windows Server 2008 使用WSUS实现内网计算机系统更新
- Lua的系统学习(杂)_通过Lua调用C#方法(热更新最直观的原理理解)_简单的随机数实现
- 如何卸载Win10系统上已安装的更新补丁
- WinCe下热更新系统
- 如何实现缓存系统的更新机制
- Android 轻松实现后台搭建+APP版本更新
- 模块管理常规功能自定义系统的设计与实现(54--视频讲解更新高清 )
- Android在后台线程实现 定时更新时间
- 【干货】利用MVC5+EF6搭建博客系统(四)(上)前后台页面布局页面实现,介绍使用的UI框架以及JS组件
- 公司内网成功实现WSUS在不连外网的条件下更新补丁包!
- ABAP--如何实现交货单的任何一item库位发生人工修改时系统自动更新所有items(感谢天元提供)
- 如何在wince下实现一个文件系统驱动
- android远程控制(三)----通过后台服务实现系统点击事件模拟
- 公司内网成功实现WSUS在不连外网的条件下更新补丁包!
- 网站后台的综合管理系统的实现
- Spring AOP实现后台管理系统日志管理