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

在C#中实现软件自动升级

2007-08-09 17:58 435 查看
winform程序相对web程序而言,功能更强大,编程更方便,但软件更新却相当麻烦,要到客户端一台一台地升级,本文结合实际情况,通过软件实现自动升级,弥补了这一缺陷,有较好的参考价值。
由于程序在运行时不能用新的版本覆盖自己,因此,我们将登录窗口单独做成一个可执行文件,用户登录时,从网上检测是否有新的主程序,如果有,则从后台下载并覆盖老的版本,用户输入正确的用户名和密码后,通过参数将必要的信息(如用户名、密码等)传递给主程序,实现登录,我们还是以实际例子来说明。
创建一个项目,不妨取名为MainPro,作为主程序,切换到代码窗口,看到如下一段代码:
[align=left] /// <summary>[/align]
[align=left] /// 应用程序的主入口点。[/align]
[align=left] /// </summary>[/align]
[align=left] [STAThread][/align]
[align=left] static void Main() [/align]
[align=left] {[/align]
[align=left] Application.Run(new Form1());[/align]
}
为了接收参数,我们添加两个静态变量m_UserName和m_Password用于存放用户名和密码,并修改Main函数为:
[align=left] private static string m_UserName,m_Password;[/align]
[align=left] /// <summary>[/align]
[align=left] /// 应用程序的主入口点。[/align]
[align=left] /// </summary>[/align]
[align=left] [STAThread][/align]
[align=left] static void Main(string[] args) [/align]
[align=left] {[/align]
[align=left] if(args.Length==2)//有参数输入,你还可以根据实际情况传入更多参数[/align]
[align=left] {[/align]
[align=left] //记录下用户名和密码,供软件使用[/align]
[align=left] m_UserName=args[0];[/align]
[align=left] m_Password=args[1];[/align]
[align=left] Application.Run(new Form1());[/align]
[align=left] }[/align]
[align=left] else[/align]
[align=left] {[/align]
[align=left] MessageBox.Show("不能从这里启动");[/align]
[align=left] }[/align]
}
为了显示登录是否正确,Load事件的代码修改为:
[align=left] private void Form1_Load(object sender, System.EventArgs e)[/align]
[align=left] {[/align]
[align=left] string msg=string.Format("用户名:{0},密码:{1}",m_UserName,m_Password);[/align]
[align=left] MessageBox.Show(msg);[/align]
}
这样,我们的示例主程序就完成了,只有加入参数才能运行该主程序,例如我们在DOS窗口中用“mainpro user pass”来启动该软件。
由于本项目涉及到不止一个程序,为保证运行正确,需要将编译后的可执行文件放到同一个文件夹,尽管我们可以编译后再将文件复制到同一个文件夹中,但每次都手工复制比较费事,这里采取一个简单的办法。先在硬盘中创建一个文件夹,如D:/output,选择菜单“项目”→“属性”,会弹出一个对话框,在配置(C)后面选择“所有配置”,选择配置属性的生成项,在输出路径中输入“D:/output”(如下图),再编译时你就发现,输出的可执行文件乖乖地跑到D:/output下面了。

接下来做一个上传工具,目的是将最新版本上传到服务器上,为简单,我们这里使用access数据库,当然,在网络版中可以使用SQL Server,原理完全一样。
在D:/output下新建一个access数据库,取名为mydatabase.mdb吧,新建两个表,一个为操作员,用来存放操作员的姓名和密码,另外一个为版本,用来存放主程序的最新版本,两个表的结构如下:
[align=center]操作员表[/align]
[align=center]版本表[/align]
[align=center]字段名[/align]
[align=center]类型[/align]
[align=center]用途[/align]
[align=center]字段名[/align]
[align=center]类型[/align]
[align=center]用途[/align]
[align=center]序号[/align]
[align=center]长整型[/align]
[align=center]主键[/align]
[align=center]序号[/align]
[align=center]长整型[/align]
[align=center]主键[/align]
[align=center]姓名[/align]
[align=center]字符[/align]
[align=center]用户名[/align]
[align=center]版本号[/align]
[align=center]长整型[/align]
[align=center]存放当前版本[/align]
[align=center]文件名称[/align]
[align=center]字符[/align]
本记录对应的文件名
[align=center]密码[/align]
[align=center]字符[/align]
[align=center]密码[/align]
[align=center]文件内容[/align]
OLE 对象,SQL 中为Image
[align=center]存放文件的具体内容[/align]
我们手工输入一些用户名和密码,如下:
[align=center][/align]
不要关闭刚才的主程序,直接选择菜单“文件”→“添加项目”→“新建项目”,输入项目名称为“UpLoad”,如下图:
[align=center][/align]
点“确定”,同样,配置输出路径为D:/output。
在窗口上放入三个按钮(浏览(btnBrow)、确定(btnOK)和取消(btnCancel))、两个文本框(txtFileName,txtVersion)和相应的文字说明,如下图:
[align=center][/align]
在“解决方案资源管理器”窗口中,选择“upload”项目,单击鼠标右键,选择“设为启动项目”,就可以运行该程序了。
添加浏览按钮的响应代码如下:
[align=left] private void btnBrow_Click(object sender, System.EventArgs e)[/align]
[align=left] {[/align]
[align=left] OpenFileDialog myForm=new OpenFileDialog();[/align]
[align=left] myForm.Filter="应用程序(*.exe)|*.exe|所有程序(*.*)|*.*";[/align]
[align=left] if(myForm.ShowDialog()==DialogResult.OK)[/align]
[align=left] {[/align]
[align=left] this.txtFileName.Text=myForm.FileName;[/align]
[align=left] }[/align]
}
该按钮的作用是得到要上传文件的文件名称(实际应用中,还可以根据得到的文件名,从数据库中得到相对应文件的最高版本号,自动填入的版本号文本框中供输入新版本号时参考)。
添加取消按钮响应代码,目的是关闭窗口:
[align=left] private void btnCancel_Click(object sender, System.EventArgs e)[/align]
[align=left] {[/align]
[align=left] this.Close();[/align]
}
添加两个引用:
[align=left] using System.Data.OleDb;[/align]
[align=left] using System.IO;[/align]
再添加两个变量:
[align=left] private DataSet m_DataSet=new DataSet();[/align]
[align=left] private string m_TableName="版本";[/align]
下面的函数去掉文件名中的路径:
[align=left] /// <summary>[/align]
[align=left] /// 从一个含有路径的文件名中分离出文件名[/align]
[align=left] /// </summary>[/align]
[align=left] /// <param name="p_Path">包含路径的文件名</param>[/align]
[align=left] /// <returns>去掉路径的文件名</returns>[/align]
[align=left] private string GetFileNameFromPath(string p_Path)[/align]
[align=left] {[/align]
[align=left] string strResult="";[/align]
[align=left] int nStart=p_Path.LastIndexOf("//");[/align]
[align=left] if(nStart>0)[/align]
[align=left] {[/align]
[align=left] strResult=p_Path.Substring(nStart+1,p_Path.Length-nStart-1);[/align]
[align=left] }[/align]
[align=left] return strResult;[/align]
}
添加确定按钮响应代码(含注释):
[align=left]private void btnOK_Click(object sender, System.EventArgs e)[/align]
[align=left] {[/align]
[align=left] //检查版本号是否合法[/align]
[align=left] try[/align]
[align=left] {[/align]
[align=left] Decimal.Parse(this.txtVersion.Text);[/align]
[align=left] }[/align]
[align=left] catch[/align]
[align=left] {[/align]
[align=left] MessageBox.Show("无效的版本号!");[/align]
[align=left] this.txtVersion.Focus();[/align]
[align=left] this.txtVersion.SelectAll();[/align]
[align=left] return;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] if(this.txtFileName.Text.Trim().Length>0)[/align]
[align=left] {[/align]
[align=left] //检查文件是否存在[/align]
[align=left] if(!File.Exists(this.txtFileName.Text.Trim()))[/align]
[align=left] {[/align]
[align=left] MessageBox.Show("文件不存在!");[/align]
[align=left] return;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] //连接数据库[/align]
[align=left] string strConnection="Provider = Microsoft.Jet.OLEDB.4.0 ;Jet OLEDB:Database Password=;Data Source ="+[/align]
[align=left] Application.StartupPath.ToString().Trim()+"//mydatabase.mdb" ;[/align]
[align=left] OleDbConnection myConnect=new OleDbConnection(strConnection);[/align]
[align=left] OleDbCommand myCommand=new OleDbCommand("select * from 版本",myConnect);[/align]
[align=left] OleDbDataAdapter myDataAdapter=new OleDbDataAdapter();[/align]
[align=left] myDataAdapter.SelectCommand=myCommand;[/align]
[align=left] OleDbCommandBuilder myCommandBuilder=new OleDbCommandBuilder(myDataAdapter);[/align]
[align=left] myConnect.Open();[/align]
[align=left] [/align]
[align=left] //获取已有的数据[/align]
[align=left] m_DataSet=new DataSet();[/align]
[align=left] try[/align]
[align=left] {[/align]
[align=left] myDataAdapter.Fill(m_DataSet,this.m_TableName);[/align]
[align=left] //如果是首次上传,则增加一条记录[/align]
[align=left] if(m_DataSet.Tables[m_TableName].Rows.Count==0)[/align]
[align=left] {[/align]
[align=left] DataRow newrow=m_DataSet.Tables[m_TableName].NewRow();[/align]
[align=left] newrow["序号"]="1";[/align]
[align=left] m_DataSet.Tables[m_TableName].Rows.Add(newrow);[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] DataRow row=m_DataSet.Tables[m_TableName].Rows[0];[/align]
[align=left] //填入去掉路径的文件名称[/align]
[align=left] row["文件名称"]=this.GetFileNameFromPath(this.txtFileName.Text.Trim());[/align]
[align=left] //填入版本号[/align]
[align=left] row["版本号"]=this.txtVersion.Text.Trim();[/align]
[align=left] [/align]
[align=left] //将实际文件存入记录中[/align]
[align=left] FileStream fs=new FileStream(this.txtFileName.Text.Trim(),FileMode.Open);[/align]
[align=left] byte [] myData = new Byte [fs.Length ];[/align]
[align=left] fs.Position = 0;[/align]
[align=left] fs.Read (myData,0,Convert.ToInt32 (fs.Length ));[/align]
[align=left] row["文件内容"] = myData;[/align]
[align=left] fs.Close();//关闭文件[/align]
[align=left] [/align]
[align=left] //更新数据库[/align]
[align=left] myDataAdapter.Update(this.m_DataSet,this.m_TableName);[/align]
[align=left] myConnect.Close();[/align]
[align=left] MessageBox.Show("文件更新成功!");[/align]
[align=left] }[/align]
[align=left] catch(Exception ee)[/align]
[align=left] {[/align]
[align=left] MessageBox.Show(ee.Message);[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] else[/align]
[align=left] {[/align]
[align=left] MessageBox.Show("请输入文件名");[/align]
[align=left] }[/align]
}
至此,上传工具制作完成,通过该程序,可以上传主程序文件,当然,该工具是给软件开发供应商用于发布新软件用的,千万不要给用户哦。
最后是编写登录程序,按照编写上传工具的方法添加一个项目,项目名称为Login,设置输出路径为D:/Output,并设置该项目为启动项目。
添加一个组合框(combUserName),设置DropDownStyle为DropDownList,用来选择已有的用户名,添加一个用于输入密码的文本框(txtPassword),设置PasswordChar属性为“*”,并在前面加入相应的文字标签,再添加确定(btnOK)和取消(btnCancel)按钮,并将确定按钮的Enable属性设置为false,目的是如果新软件没有下载完成,不准登录,布置如下图:
[align=center][/align]
切换到代码窗口,添加引用:
using System.Data.OleDb;
using System.Threading;
using System.IO;
using Microsoft.Win32;

再添加如下变量:
[align=left] /// <summary>[/align]
[align=left] /// 存放操作员及密码的DataSet[/align]
[align=left] /// </summary>[/align]
[align=left] private DataSet m_DataSet;[/align]
[align=left] /// <summary>[/align]
[align=left] /// 本功能用到的数据库表[/align]
[align=left] /// </summary>[/align]
[align=left] private string m_TableName="操作员";[/align]
[align=left] private DataTable m_Table;[/align]
为了避免每次都下载主程序,我们将当前主程序的版本号要保存下来,我采用的办法是保存到注册表中,为此,写两个函数,用于读取/写入注册表,如下:
[align=left] /// <summary>[/align]
[align=left] /// 定义本软件在注册表中software下的公司名和软件名称[/align]
[align=left] /// </summary>[/align]
[align=left] private string m_companyname="lqjt",m_softwarename="autologin";[/align]
[align=left] /// <summary>[/align]
[align=left] /// 从注册表中读信息;[/align]
[align=left] /// </summary>[/align]
[align=left] /// <param name="p_KeyName">要读取的键值</param>[/align]
[align=left] /// <returns>读到的键值字符串,如果失败(如注册表尚无信息),则返回""</returns>[/align]
[align=left] private string ReadInfo(string p_KeyName)[/align]
[align=left] {[/align]
[align=left] RegistryKey SoftwareKey=Registry.LocalMachine.OpenSubKey("Software",true);[/align]
[align=left] RegistryKey CompanyKey=SoftwareKey.OpenSubKey(m_companyname);[/align]
[align=left] string strValue="";[/align]
[align=left] [/align]
[align=left] if(CompanyKey==null)[/align]
[align=left] return "";[/align]
[align=left] RegistryKey SoftwareNameKey=CompanyKey.OpenSubKey(m_softwarename);//建立[/align]
[align=left] if(SoftwareNameKey==null)[/align]
[align=left] return "";[/align]
[align=left] [/align]
[align=left] try[/align]
[align=left] {[/align]
[align=left] strValue=SoftwareNameKey.GetValue(p_KeyName).ToString().Trim();[/align]
[align=left] }[/align]
[align=left] catch[/align]
[align=left] {}[/align]
[align=left] [/align]
[align=left] if(strValue==null)[/align]
[align=left] strValue="";[/align]
[align=left] return strValue;[/align]
[align=left] }[/align]
[align=left] /// <summary>[/align]
[align=left] /// 将信息写入注册表[/align]
[align=left] /// </summary>[/align]
[align=left] /// <param name="p_keyname">键名</param>[/align]
[align=left] /// <param name="p_keyvalue">键值</param>[/align]
[align=left] private void WriteInfo(string p_keyname,string p_keyvalue)[/align]
[align=left] {[/align]
[align=left] RegistryKey SoftwareKey=Registry.LocalMachine.OpenSubKey("Software",true);[/align]
[align=left] RegistryKey CompanyKey=SoftwareKey.CreateSubKey(m_companyname);[/align]
[align=left] RegistryKey SoftwareNameKey=CompanyKey.CreateSubKey(m_softwarename);[/align]
[align=left] //写入相应信息[/align]
[align=left] SoftwareNameKey.SetValue(p_keyname,p_keyvalue);[/align]
}
再写一个函数,用户来获取用户名/密码和更新主程序版本:
[align=left]/// <summary>[/align]
[align=left] /// 获取操作员情况,同时更新主程序版本[/align]
[align=left] /// </summary>[/align]
[align=left] private void GetInfo()[/align]
[align=left] {[/align]
[align=left] this.m_DataSet=new DataSet();[/align]
[align=left] this.combUsers.Items.Clear();[/align]
[align=left] string strSql=string.Format("SELECT * FROM 操作员 ORDER BY 姓名");[/align]
[align=left] [/align]
[align=left] //连接数据库[/align]
[align=left] string strConnection="Provider = Microsoft.Jet.OLEDB.4.0 ;Jet OLEDB:Database Password=;Data Source ="+[/align]
[align=left] Application.StartupPath.ToString().Trim()+"//mydatabase.mdb" ;[/align]
[align=left] OleDbConnection myConnect=new OleDbConnection(strConnection);[/align]
[align=left] OleDbCommand myCommand=new OleDbCommand(strSql,myConnect);[/align]
[align=left] OleDbDataAdapter myDataAdapter=new OleDbDataAdapter();[/align]
[align=left] myDataAdapter.SelectCommand=myCommand;[/align]
[align=left] try[/align]
[align=left] {[/align]
[align=left] myConnect.Open();[/align]
[align=left] [/align]
[align=left] //获取操作员信息[/align]
[align=left] myDataAdapter.Fill(this.m_DataSet,this.m_TableName);[/align]
[align=left] //将查询到的用户名填充到组合框供用户选择[/align]
[align=left] this.m_Table=this.m_DataSet.Tables[this.m_TableName];[/align]
[align=left] foreach(DataRow row in m_DataSet.Tables[m_TableName].Rows)[/align]
[align=left] {[/align]
[align=left] this.combUsers.Items.Add(row["姓名"]).ToString().Trim();[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] //检查是否有新的版本[/align]
[align=left] DataSet dataset=new DataSet();[/align]
[align=left] string tablename="tablename";[/align]
[align=left] //为减少数据传送时间,不获取文件内容[/align]
[align=left] strSql="select 文件名称,版本号 from 版本";[/align]
[align=left] myCommand=new OleDbCommand(strSql,myConnect);[/align]
[align=left] myDataAdapter=new OleDbDataAdapter();[/align]
[align=left] myDataAdapter.SelectCommand=myCommand;[/align]
[align=left] myDataAdapter.Fill(dataset,tablename);[/align]
[align=left] if(dataset.Tables[tablename].Rows.Count==1)//有文件[/align]
[align=left] {[/align]
[align=left] string filename=dataset.Tables[tablename].Rows[0]["文件名称"].ToString();[/align]
[align=left] string version=dataset.Tables[tablename].Rows[0]["版本号"].ToString();[/align]
[align=left] //读入本机主程序的版本号[/align]
[align=left] string oldversion=this.ReadInfo(filename);[/align]
[align=left] if(oldversion.Length==0)//不存在[/align]
[align=left] oldversion="0";[/align]
[align=left] if(Decimal.Parse(version)>Decimal.Parse(oldversion))//有新的版本出现[/align]
[align=left] {[/align]
[align=left] //取回文件内容[/align]
[align=left] dataset=new DataSet();[/align]
[align=left] strSql="select * from 版本";[/align]
[align=left] myCommand=new OleDbCommand(strSql,myConnect);[/align]
[align=left] myDataAdapter=new OleDbDataAdapter();[/align]
[align=left] myDataAdapter.SelectCommand=myCommand;[/align]
[align=left] myDataAdapter.Fill(dataset,tablename);[/align]
[align=left] //将文件下载到本地[/align]
[align=left] DataRow row=dataset.Tables[tablename].Rows[0];[/align]
[align=left] if(row["文件内容"]!=DBNull.Value)[/align]
[align=left] {[/align]
[align=left] [/align]
[align=left] Byte[] byteBLOBData = new Byte[0];[/align]
[align=left] byteBLOBData = (Byte[])row["文件内容"];[/align]
[align=left] try[/align]
[align=left] {[/align]
[align=left] FileStream fs=new FileStream(Application.StartupPath+"//"+filename,FileMode.OpenOrCreate);[/align]
[align=left] fs.Write(byteBLOBData,0,byteBLOBData.Length);[/align]
[align=left] fs.Close();[/align]
[align=left] //写入当前版本号,供下次使用[/align]
[align=left] this.WriteInfo(filename,version);[/align]
[align=left] }[/align]
[align=left] catch(Exception ee)[/align]
[align=left] {[/align]
[align=left] MessageBox.Show(ee.Message);[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] }//有新版本[/align]
[align=left] }//有文件[/align]
[align=left] [/align]
[align=left] //关闭连接[/align]
[align=left] myConnect.Close();[/align]
[align=left] }[/align]
[align=left] catch(Exception ee)[/align]
[align=left] {[/align]
[align=left] MessageBox.Show(ee.Message);[/align]
[align=left] return;[/align]
[align=left] }[/align]
[align=left] //允许登录[/align]
[align=left] this.btnOK.Enabled=true;[/align]
}
为了不让用户等待太久,在启动时通过一个线程,让获取用户信息和更新在后台完成,即在窗口Load事件中,通过线程调用上面的GetInfo的函数,故窗口Load代码如下:
[align=left] private void Form1_Load(object sender, System.EventArgs e)[/align]
[align=left] {[/align]
[align=left] //为加快显示速度,将数据库连接等放到另外一个线程中去[/align]
[align=left] Thread thread=new Thread(new ThreadStart(GetInfo));[/align]
[align=left] thread.Start();[/align]
}
有了上述准备,我们来编写确定按钮的响应代码如下:
[align=left]private void btnOK_Click(object sender, System.EventArgs e)[/align]
[align=left] {[/align]
[align=left] //根据组合框的选择,得到当前用户在DataSet中具体物理位置[/align]
[align=left] if(this.combUsers.SelectedIndex<0)//没有选择[/align]
[align=left] return;[/align]
[align=left] DataRow rowNow=null;[/align]
[align=left] foreach(DataRow row in this.m_DataSet.Tables[this.m_TableName].Rows)[/align]
[align=left] {[/align]
[align=left] if(row["姓名"].ToString().Trim()==this.combUsers.Text.Trim())[/align]
[align=left] {[/align]
[align=left] rowNow=row;[/align]
[align=left] break;[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] if(rowNow==null)[/align]
[align=left] return;[/align]
[align=left] [/align]
[align=left] //获取当前正确密码[/align]
[align=left] string strPassword=rowNow["密码"].ToString().Trim();[/align]
[align=left] this.txtPassword.Text=this.txtPassword.Text.Trim();[/align]
[align=left] if(this.txtPassword.Text==strPassword)//密码正确[/align]
[align=left] {[/align]
[align=left] [/align]
[align=left] //主程序名称[/align]
[align=left] string filename=Application.StartupPath+"//"+"MainPro.exe";[/align]
[align=left] //参数名称[/align]
[align=left] string arg=this.combUsers.Text+" "+this.txtPassword.Text;[/align]
[align=left] //运行主程序[/align]
[align=left] System.Diagnostics.Process fun=System.Diagnostics.Process.Start(filename,arg);[/align]
[align=left] [/align]
[align=left] //关闭登录框[/align]
[align=left] this.Close();[/align]
[align=left] }[/align]
[align=left] else[/align]
[align=left] {[/align]
[align=left] MessageBox.Show(" 密码错误!如果你确信密码输入正确,/n可以试着检查一下大写字母键是否按下去了。",[/align]
[align=left] "警告",MessageBoxButtons.OK,MessageBoxIcon.Warning);[/align]
[align=left] this.txtPassword.Focus();[/align]
[align=left] this.txtPassword.SelectAll();[/align]
[align=left] }[/align]
}
取消按钮的代码非常简单,就是关闭登录窗口:
[align=left] private void btnCancel_Click(object sender, System.EventArgs e)[/align]
[align=left] {[/align]
[align=left] this.Close();[/align]
}
把Login和MainPro软件连同其他相关文件打包成安装程序,将Login以快捷方式放到桌面或开始菜单中供用户使用(当然,快捷方式名称可以随便取了),用户运行Login后,会自动更新软件。
本例中所有代码请到ftp://qydn.vicp.net/ 下载,文件名为update.rar,解压缩后别忘了在D:/创建一个output文件夹,并将mydatabase.mdb复制到该文件夹中。
说明:本文只起抛砖引玉的作用,通过该思路进行扩展可以完成许多功能,如通过修改上传/登录程序,不仅可以实现对主程序的更新,而且可以实现对任何要用到的资源文件进行更新,本例中不能实现对登录框本身的更新,我采用的办法是在主程序的Closing事件中更新登录窗口,因为此时登录窗口已经关闭了。在登录窗口中,可以放一个“保存密码”的复选框,如果用户选中该组合框,可以将用户名和密码保存到注册表中,下次登录时直接读入,用户只要点确定按钮即可,免去了每次都选用户名和输密码的烦恼,
在本例中,我们可以看到,数据库的连接、查询等工作是重复性劳动,且三个个项目中用到的数据库、公司名称等是一样的,在实际工作中,我们可以单独新建一个cs文件,不妨取名为MyTools.cs,将一些常用函数和变量(如数据库连接、公司名称等)做成静态的,各具体项目中链接本文件,然后直接使用,我们只需修改MyTools.cs中的相关变量或函数而不必在每个项目中都去改,既方便又不会遗漏,MyTools.cs参考如下:
[align=left]///<summary>[/align]
[align=left]///预编译选项,如果定义了NETWORKVERSION,,表示是网络版,使用SQL2000数据库,否则,使用ACCESS2000数据库[/align]
[align=left]///</summary>[/align]
[align=left] [/align]
[align=left]//#define NETWORKVERSION[/align]
[align=left] [/align]
[align=left]using System;[/align]
[align=left]using System.Drawing;[/align]
[align=left]using System.Collections;[/align]
[align=left]using System.ComponentModel;[/align]
[align=left]using System.Windows.Forms;[/align]
[align=left]using System.Drawing.Imaging;[/align]
[align=left]using System.IO;[/align]
[align=left]using System.Data;[/align]
[align=left] [/align]
[align=left]#if NETWORKVERSION[/align]
[align=left]using System.Data.SqlClient;[/align]
[align=left]#else[/align]
[align=left]using System.Data.OleDb;[/align]
[align=left]#endif[/align]
[align=left]using System.Reflection;[/align]
[align=left]using Microsoft.Win32;[/align]
[align=left] [/align]
[align=left]namespace OA[/align]
[align=left]{[/align]
[align=left] public class Tool[/align]
[align=left] {[/align]
[align=left] public Tool()[/align]
[align=left] {[/align]
[align=left] }[/align]
[align=left] /// <summary>[/align]
[align=left] /// 主程序的文件名[/align]
[align=left] /// </summary>[/align]
[align=left] public const string FileName="OA.exe";[/align]
public const string g_TitleName="丽汽集团办公自动化系统";
public static string g_UserName;
[align=left] public static void WriteInfo(string p_keyname,string p_keyvalue)[/align]
[align=left] {[/align]
[align=left] ……[/align]
}
[align=left]//其他类似代码略……[/align]
[align=left] [/align]
}
}
如果一个项目中要用到MyTools中的内容,可以按如下方式进行:
在“解决方案资源管理器”窗口中选择该项目,选择菜单“项目”→“添加现有项”,此时弹出打开文件对话框,文件类型设为所有文件(*.*),找到MyTools.cs,不要直接点打开按钮,看到了打开按钮后面的“↓”了吗?单击它可以弹出一个菜单,选择“链接文件(L)”,这样插入的文件只是一个链接,不会生成副本(如下图)。

使用时,添加MyTools的应用,再使用Tool类中的公共函数,如:
using OA;
private void myFun()
{
string s=Tool.FileName;
}
如果单位名称变了,我们只要修改MyTools.cs中的变量就可以了,不必到每个项目中都去修改。
我们还注意了一个细节:
[align=left]///<summary>[/align]
[align=left]///预编译选项,如果定义了NETWORKVERSION,,表示是网络版,使用SQL2000数据库,否则,使用ACCESS2000数据库[/align]
[align=left]///</summary>[/align]
[align=left] [/align]
[align=left]//#define NETWORKVERSION[/align]
我们知道,对于ACCESS或Sql server等,除了连接方式外,其余操作几乎完全一样,因此,我们定义了一个选项(如上面的注释),如果#define NETWORKVERSION,表示是网络版,使用Sql server数据库,否则(将#define NETWORKVERSION注释掉)就是单机版,使用ACCESS数据库,在MyTools中我们将两种连接方式有区别的地方分别编写,就可以通过是否注释掉#define NETWORKVERSION这一行分别生成单机版和网络版软件,参考代码如下:
[align=left] /// <summary>[/align]
[align=left] /// 根据SQL语句返回一个查询结果,主要用于只要求返回一个字段的一个结果的情况[/align]
[align=left] /// </summary>[/align]
[align=left] /// <param name="p_Sql">查询用到的SQL语句</param>[/align]
[align=left] /// <returns>查询到的结果,没有时则返回空""</returns>[/align]
[align=left] public static string GetAValue(string p_Sql)[/align]
[align=left] {[/align]
[align=left] string strResult="";[/align]
[align=left] Tool.OpenConn();[/align]
[align=left] [/align]
[align=left] //设计所需要返回的数据集的内容 [/align]
[align=left] try [/align]
[align=left] { [/align]
[align=left] // 打开指向数据库连接 [/align]
[align=left]#if NETWORKVERSION //网络版[/align]
[align=left] SqlCommand aCommand = new SqlCommand ( p_Sql ,m_Connect ) ;[/align]
[align=left] SqlDataReader aReader = aCommand.ExecuteReader ( ) ; [/align]
[align=left]#else //单机版,注意变量名aCommand和aReader在两个版本中都是一样的,有利于编程[/align]
[align=left] OleDbCommand aCommand = new OleDbCommand ( p_Sql ,m_Connect ) ;[/align]
[align=left] OleDbDataReader aReader = aCommand.ExecuteReader ( ) ; [/align]
[align=left]#endif[/align]
[align=left] [/align]
[align=left] // 返回需要的数据集内容这里就不分单机版还是网络版了,反正变量名一样[/align]
[align=left] if(aReader.Read())[/align]
[align=left] strResult=aReader[0].ToString();[/align]
[align=left] aReader.Close () ; [/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] catch(Exception ee)[/align]
[align=left] {[/align]
[align=left] MessageBox.Show(ee.Message);[/align]
[align=left] }[/align]
[align=left] return strResult;[/align]
}
以上类似的小技巧还很多,注意总结,定会收益多多。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: