您的位置:首页 > 编程语言 > C#

C#实现软件自动升级代码【编程联盟】

2009-10-12 14:47 495 查看
 C#实现软件自动升级代码【编程联盟】
【转】http://www.bcbbs.net/html/55678.html

 

 

winform程序相对web程序而言,功能更强大,编程更方便,但软件更新却相当麻烦,要到客户端一台一台地升级,本文结合实际情况,通过软件实现自动升级,弥补了这一缺陷,有较好的参考价值。

由于程序在运行时不能用新的版本覆盖自己,因此,我们将登录窗口单独做成一个可执行文件,用户登录时,从网上检测是否有新的主程序,如果有,则从后台下载并覆盖老的版本,用户输入正确的用户名和密码后,通过参数将必要的信息(如用户名、密码等)传递给主程序,实现登录,我们还是以实际例子来说明。

创建一个项目,不妨取名为MainPro,作为主程序,切换到代码窗口,看到如下一段代码:
         ///
         /// 应用程序的主入口点。
         ///
         [STAThread]
         static void Main()
         {
              Application.Run(new Form1());
      }

为了接收参数,我们添加两个静态变量m_UserName和m_Password用于存放用户名和密码,并修改Main函数为:

         private static string m_UserName,m_Password;
         ///
         /// 应用程序的主入口点。
         ///
         [STAThread]
         static void Main(string[] args)
         {
              if(args.Length==2)//有参数输入,你还可以根据实际情况传入更多参数
              {
                  //记录下用户名和密码,供软件使用
                   m_UserName=args[0];
                   m_Password=args[1];
                   Application.Run(new Form1());
              }
              else
              {
                   MessageBox.Show("不能从这里启动");
              }
      }

为了显示登录是否正确,Load事件的代码修改为:

         private void Form1_Load(object sender, System.EventArgs e)
         {
              string msg=string.Format("用户名:{0},密码:{1}",m_UserName,m_Password);
              MessageBox.Show(msg);

      }

这样,我们的示例主程序就完成了,只有加入参数才能运行该主程序,例如我们在DOS窗口中用"mainpro user pass"来启动该软件。

由于本项目涉及到不止一个程序,为保证运行正确,需要将编译后的可执行文件放到同一个文件夹,尽管我们可以编译后再将文件复制到同一个文件夹中,但每次都手工复制比较费事,这里采取一个简单的办法。先在硬盘中创建一个文件夹,如D:/output,选择菜单"项目"→"属性",会弹出一个对话框,在配置(C)后面选择"所有配置",选择配置属性的生成项,在输出路径中输入"D:/output"(如下图),再编译时你就发现,输出的可执行文件乖乖地跑到D:/output下面了。

 

接下来做一个上传工具,目的是将最新版本上传到服务器上,为简单,我们这里使用access数据库,当然,在网络版中可以使用SQL Server,原理完全一样。

在D:/output下新建一个access数据库,取名为mydatabase.mdb吧,新建两个表,一个为操作员,用来存放操作员的姓名和密码,另外一个为版本,用来存放主程序的最新版本,两个表的结构如下:

操作员表
版本表
字段名
类型
用途
字段名
类型
用途
序号
长整型
主键
序号
长整型
主键
姓名
字符
用户名
版本号
长整型
存放当前版本
文件名称
字符
本记录对应的文件名

密码
字符
密码
文件内容
OLE 对象,SQL 中为Image

存放文件的具体内容
我们手工输入一些用户名和密码,如下:

 
不要关闭刚才的主程序,直接选择菜单"文件"→"添加项目"→"新建项目",输入项目名称为"UpLoad",如下图:

 
点"确定",同样,配置输出路径为D:/output。

在窗口上放入三个按钮(浏览(btnBrow)、确定(btnOK)和取消(btnCancel))、两个文本框(txtFileName,txtVersion)和相应的文字说明,如下图:

 
在"解决方案资源管理器"窗口中,选择"upload"项目,单击鼠标右键,选择"设为启动项目",就可以运行该程序了。

添加浏览按钮的响应代码如下:

         private void btnBrow_Click(object sender, System.EventArgs e)
         {
              OpenFileDialog myForm=new OpenFileDialog();
              myForm.Filter="应用程序(*.exe)|*.exe|所有程序(*.*)|*.*";
              if(myForm.ShowDialog()==DialogResult.OK)
              {
                   this.txtFileName.Text=myForm.FileName;
              }
      }

该按钮的作用是得到要上传文件的文件名称(实际应用中,还可以根据得到的文件名,从数据库中得到相对应文件的最高版本号,自动填入的版本号文本框中供输入新版本号时参考)。

添加取消按钮响应代码,目的是关闭窗口:

         private void btnCancel_Click(object sender, System.EventArgs e)
         {
              this.Close();
      }

添加两个引用:

         using System.Data.OleDb;
         using System.IO;

再添加两个变量:

         private DataSet m_DataSet=new DataSet();
         private string m_TableName="版本";

下面的函数去掉文件名中的路径:

         ///
         /// 从一个含有路径的文件名中分离出文件名
         ///
         /// 包含路径的文件名
         /// 去掉路径的文件名
         private string GetFileNameFromPath(string p_Path)
         {
              string strResult="";
              int nStart=p_Path.LastIndexOf("//");
              if(nStart>0)
              {
                   strResult=p_Path.Substring(nStart+1,p_Path.Length-nStart-1);
              }
              return strResult;
      }

添加确定按钮响应代码(含注释):

private void btnOK_Click(object sender, System.EventArgs e)
         {
              //检查版本号是否合法
              try
              {
                   Decimal.Parse(this.txtVersion.Text);
              }
              catch
              {
                   MessageBox.Show("无效的版本号!");
                   this.txtVersion.Focus();
                   this.txtVersion.SelectAll();
                   return;
              }

              if(this.txtFileName.Text.Trim().Length>0)
              {
                   //检查文件是否存在
                   if(!File.Exists(this.txtFileName.Text.Trim()))
                   {
                       MessageBox.Show("文件不存在!");
                       return;
                   }

                   //连接数据库
                   string strConnection="Provider = Microsoft.Jet.OLEDB.4.0 ;Jet OLEDB:Database Password=;Data Source ="+
                                          Application.StartupPath.ToString().Trim()+"//mydatabase.mdb" ;
                   OleDbConnection myConnect=new OleDbConnection(strConnection);
                   OleDbCommand myCommand=new OleDbCommand("select * from 版本",myConnect);
                   OleDbDataAdapter myDataAdapter=new OleDbDataAdapter();
                   myDataAdapter.SelectCommand=myCommand;
                   OleDbCommandBuilder myCommandBuilder=new OleDbCommandBuilder(myDataAdapter);
                   myConnect.Open();

                   //获取已有的数据
                   m_DataSet=new DataSet();
                   try
                   {
                       myDataAdapter.Fill(m_DataSet,this.m_TableName);
                       //如果是首次上传,则增加一条记录
                       if(m_DataSet.Tables[m_TableName].Rows.Count==0)
                       {
                            DataRow newrow=m_DataSet.Tables[m_TableName].NewRow();
                            newrow["序号"]="1";
                            m_DataSet.Tables[m_TableName].Rows.Add(newrow);
                       }
                      
                       DataRow row=m_DataSet.Tables[m_TableName].Rows[0];
                       //填入去掉路径的文件名称
                       row["文件名称"]=this.GetFileNameFromPath(this.txtFileName.Text.Trim());
                       //填入版本号
                       row["版本号"]=this.txtVersion.Text.Trim();

                       //将实际文件存入记录中
                       FileStream fs=new FileStream(this.txtFileName.Text.Trim(),FileMode.Open);
                       byte [] myData = new Byte [fs.Length ];
                       fs.Position = 0;
                       fs.Read (myData,0,Convert.ToInt32 (fs.Length ));
                       row["文件内容"] = myData;
                       fs.Close();//关闭文件

                       //更新数据库
                       myDataAdapter.Update(this.m_DataSet,this.m_TableName);
                        myConnect.Close();
                       MessageBox.Show("文件更新成功!");
                   }
                   catch(Exception ee)
                   {
                       MessageBox.Show(ee.Message);
                   }
                  
              }
              else
              {
                   MessageBox.Show("请输入文件名");
              }
      }

至此,上传工具制作完成,通过该程序,可以上传主程序文件,当然,该工具是给软件开发供应商用于发布新软件用的,千万不要给用户哦。

最后是编写登录程序,按照编写上传工具的方法添加一个项目,项目名称为Login,设置输出路径为D:/Output,并设置该项目为启动项目。

添加一个组合框(combUserName),设置DropDownStyle为DropDownList,用来选择已有的用户名,添加一个用于输入密码的文本框(txtPassword),设置PasswordChar属性为"*",并在前面加入相应的文字标签,再添加确定(btnOK)和取消(btnCancel)按钮,并将确定按钮的Enable属性设置为false,目的是如果新软件没有下载完成,不准登录,布置如下图:

 
切换到代码窗口,添加引用:

using System.Data.OleDb;
using System.Threading;
using System.IO;
using Microsoft.Win32;

再添加如下变量:

         ///
         /// 存放操作员及密码的DataSet
         ///
         private DataSet m_DataSet;
         ///
         /// 本功能用到的数据库表
         ///
         private string m_TableName="操作员";
         private DataTable m_Table;

为了避免每次都下载主程序,我们将当前主程序的版本号要保存下来,我采用的办法是保存到注册表中,为此,写两个函数,用于读取/写入注册表,如下:

         ///
         /// 定义本软件在注册表中software下的公司名和软件名称
         ///
         private string m_companyname="lqjt",m_softwarename="autologin";
         ///
         /// 从注册表中读信息;
         ///
         /// 要读取的键值
         /// 读到的键值字符串,如果失败(如注册表尚无信息),则返回""
         private string ReadInfo(string p_KeyName)
         {
              RegistryKey SoftwareKey=Registry.LocalMachine.OpenSubKey("Software",true);
              RegistryKey CompanyKey=SoftwareKey.OpenSubKey(m_companyname);
              string strValue="";
             
              if(CompanyKey==null)
                   return "";
              RegistryKey SoftwareNameKey=CompanyKey.OpenSubKey(m_softwarename);//建立
              if(SoftwareNameKey==null)
                   return "";

              try
              {
                   strValue=SoftwareNameKey.GetValue(p_KeyName).ToString().Trim();
              }
              catch
              {}

              if(strValue==null)
                   strValue="";
              return strValue;
         }
         ///
         /// 将信息写入注册表
         ///
         /// 键名
         /// 键值
         private void WriteInfo(string p_keyname,string p_keyvalue)
         {
              RegistryKey SoftwareKey=Registry.LocalMachine.OpenSubKey("Software",true);
              RegistryKey CompanyKey=SoftwareKey.CreateSubKey(m_companyname);
              RegistryKey SoftwareNameKey=CompanyKey.CreateSubKey(m_softwarename);
              //写入相应信息
              SoftwareNameKey.SetValue(p_keyname,p_keyvalue);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息