http://www.cnblogs.com/scottckt/archive/2011/05/14/2046313.html
使用VS 自帶的打包工具,製作winform安裝項目
開發環境:VS 2008 Access
操作系統:Windows XP
開發語言:C#
項目名稱:**管理系統
步驟:
第一步:打開開發環境VS2008,新建項目,選擇其他項目類型,再選擇"安裝項目",輸入名稱及選擇安裝路徑;
第二步:進入文件系統選項卡,選擇應用程序文件夾,在中間的空白區域右鍵選擇"添加文件",添加項目文件(exe,dll);
注:如果安裝項目在你的項目中。建議使用項目輸出的形式。這樣項目變更時,安裝程序也會相應的變更。如下圖。主輸出一定要選擇你要打包的項目。
第三步:添加項目所需文件;這裏有兩個文件夾需要注意(DataBase和Report),因爲DataBase是存儲項目數據庫,而Report則是存儲項目所需的報表文件.rpt,因此呢,在應用程序夾中也需要建同名的文件夾,並且添加所需的文件。效果:
第四步:爲了在開始程序菜單中和桌面應用程序中看到安裝程序,這裏我們就需要爲項目創建快捷方式。右鍵選擇可執行文件 (PersonFinance.exe),創建快捷方式,進行重命名"**公司**管理系統",將該快捷方式拖放到 '用戶的"程序"菜單' 中。重複該步驟將新建的快捷方式添加到 "用戶桌面" 文件夾中
最好在用戶菜單中建立一個文件夾,存放安裝程序
第五步:設置系統必備,右鍵選擇安裝項目,進入屬性頁中,單擊"系統必備"按鈕,進入系統必備對話框;勾選"創建用於安裝系統必備組件的安裝程序",在安裝系統必備組件列表中,選擇
1)、Windows Installer 3.1(必選)
2)、.NET Framework 3.5 (可選)參考最後說明
3)、Crystal Report Basic for Visual Studio2008(x86,x64) (可選) 項目中用到了水晶報表就需要勾選此項
重要一點:勾選"從與我的應用程序相同的位置下載系統必備組件(D)",其實意思就是說你勾選後,生成安裝項目時,在你安裝項目的路徑下,會有你在系統必備組件列表中勾選的組件.(系統自動完成,這一點還不錯,不需要你自己去下載組件)
第六步:卸載程序,因爲安裝包做好之後不能只有安裝程序,還要有卸載程序
首先呢,在"C:/WINDOWS/system32"路徑下,找到msiexec.exe 添加到應用程序文件夾中,創建快捷方式,並命名"卸載管理系統"或"Uninstall"
其次呢,選擇安裝項目的ProductCode
右鍵選擇卸載程序的快捷方式,進入屬性,在Arguments選項中 輸入/x 及ProductCode; 例如:/x {6931BD71-5C5E-4DA1-A861-14C7D1A78B97}
將卸載程序同時存放到用戶的開始菜單的文件夾中(在第四步中新建)
第七步:更改安裝程序屬性,右鍵選擇安裝項目屬性,可以設置項目作者及名稱,其他屬性信息可以根據實際情況進行設置.
第八步:生成安裝項目
生成時,會出現些警告:應將“msiexec.exe”排除,原因是其源文件“C:/WINDOWS/system32/msiexec.exe”受到“Windows 系統文件保護”。
兩個或多個對象具有相同的目標位置(“[targetdir]/model.dll”)
解決方案:
第一種:都不處理
第二種:第一類警告,可以編寫卸載程序
第二種警告:刪除相同的文件
安裝項目製作完畢.
安裝及運行:
直接運行steup.msi 或是setup.exe 會出現
在桌面和開始菜單中也會有相應的安裝程序、卸載程序。
說明及小結:
1、.net framework 框架是可選的,不一定說你採用的是VS2008開發就必須要使用.net framework 3.5,只要你在程序中沒有使用到.net framework 3.5 的特性比如(LINQ),那麼你選擇框架時,是可以選擇2.0的,爲什麼?因爲2.0只有20多MB,而3.5則有200多MB。
更改方式:在安裝項目下面有個檢測到的依賴項文件,雙擊裏面的Microsoft .net framework,進入了啓動條件選擇卡,右鍵選擇.net frmaework 在Version中選擇你所需的.net framework框架
----------------------------------------------------------------------------------------------------
安裝已會做,看看如何打包數據庫。網上已有人寫了文章,(C# WINFORM 打包數據庫):http://www.cnblogs.com/pato/archive/2010/09/16/1828276.html
實現效果:安裝項目時直接附加數據庫。
3.此時在文件系統的中間欄目,會自動列出編譯所需的文件。一個簡單項目打包差不多,還有快捷方式什麼的,就不說了。開始重點了。
創建安裝程序類
4.在解決方案資源管理器中,新建一個類庫項目【InstallDB】,刪除Class1.cs,新建一個安裝程序類[InstallDB.cs],等下將在這個類中編寫附加數據庫代碼。
5.在剛新建的安裝項目上右鍵,【視圖】->【用戶界面】:
6.然後右鍵這個文本框(A),將其上移到歡迎使用下面:
8.右鍵【自定義操作界面】的【安裝】節點,【添加自定義操作】,彈出的對話框。
9.在查找範圍裏選擇應用程序文件夾,再點擊右側的【添加輸出(O)…】,選擇剛新建的安裝程序類項目,默認還是主輸出,確定。此時:
說明:其中前四個方括號中的大寫字母,爲上面第6步圖中輸入的四個EditProPerty屬性,需要對應好。最後一個targetdir的值的意思是安裝後文件的目錄路徑。
特別提醒:前三個"/XXX=[XXX]"後面 ,都有一個空格的,小xin曾因此煩惱甚久,網上的某些教程實在是。。。很耐人。
11.現在可以添加數據庫文件了,在剛新建的安裝項目上右鍵,【添加】->【文件】,選擇你的MDF和LDF文件,就是安裝時需要附加的數據庫文件。
12.最後,我們只需在安裝程序類裏編寫附加數據庫的代碼了。打開上面第4步中新建的安裝程序類,參考下方的代碼,編寫適合您的附加數據庫代碼:
/// 附加數據庫方法
/// </summary>
/// <param name="strSql">連接數據庫字符串,連接master系統數據庫</param>
/// <param name="DataName">數據庫名字</param>
/// <param name="strMdf">數據庫文件MDF的路徑</param>
/// <param name="strLdf">數據庫文件LDF的路徑</param>
/// <param name="path">安裝目錄</param>
private void CreateDataBase( string strSql, string DataName, string strMdf, string strLdf, string path)
{
SqlConnection myConn = new SqlConnection(strSql);
String str = null ;
try
{
str = " EXEC sp_attach_db @dbname='"+DataName+"',@filename1='"+strMdf+"',@filename2='"+strLdf+"'";
SqlCommand myCommand = new SqlCommand(str, myConn);
myConn.Open();
myCommand.ExecuteNonQuery();
MessageBox.Show("數據庫安裝成功!點擊確定繼續");//需Using System.Windows.Forms
}
catch(Exception e)
{
MessageBox.Show("數據庫安裝失敗!" + e.Message+"/n/n"+"您可以手動附加數據");
System.Diagnostics.Process.Start(path);//打開安裝目錄
}
finally
{
myConn.Close();
}
}
public override void Install(System.Collections.IDictionary stateSaver)
{
string server = this.Context.Parameters["server"];//服務器名稱
string uid = this.Context.Parameters["user"];//SQlServer用戶名
string pwd = this.Context.Parameters["pwd"];//密碼
string path = this.Context.Parameters["targetdir"];//安裝目錄
string strSql = "server=" + server + ";uid=" + uid + ";pwd=" + pwd + ";database=master";//連接數據庫字符串
string DataName = "JXC";//數據庫名
string strMdf = path + @"JXC.mdf";//MDF文件路徑,這裏需注意文件名要與剛添加的數據庫文件名一樣!
string strLdf = path + @"jxc_log.ldf";//LDF文件路徑
base.Install(stateSaver);
this.CreateDataBase(strSql, DataName, strMdf, strLdf, path);//開始創建數據庫
}
--------------------------------------------------------------------------------
自已實現數據庫配置
上邊程序中是通過【添加自定義操作】實現數據庫輸入的。如果我們想在安裝時可以讓用戶有測試數據庫連接功能、並且是通過SQL語句創建數據庫,那怎麼做呢?
我們可以在上邊的自定義操作的類庫中添加一個From界面。通過它來完成。如下界面。當然,上邊文章中自定義界面的數據庫部分就可以不要了。
在上邊文章的自定義類庫中編寫代碼。
此代碼的主要功能是:
1)創建數據庫
2)創建數據庫表、存儲過程等內容
3)修改安裝程序配置文件.
public static string _serverName { get; set; }
public static string _dbName { get; set; }
public static string _userName { get; set; }
public static string _password { get; set; }
private string _setupType { get; set; }
private string _targetDir { get; set; }
/// <summary>
/// 資源中創建表結構及數據的文件名
/// </summary>
private const string _StructureAndDataFileName = "CreateStructureData";
#endregion
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
//數據庫配置 界面
frmDb dbFrom = new frmDb();
DialogResult DialogResult = dbFrom.ShowDialog();
if (DialogResult != DialogResult.OK)
{
throw new InstallException("用戶取消安裝!");
}
SqlConnection connection = null;
connection = TestConnection(_serverName, "master", _userName, _password);
//創建數據庫
int result = this.CreateDataBase(connection);
if (result > 0)
{
CloseConnection(connection);
//使用創建的數據庫
connection = TestConnection(_serverName, _dbName, _userName, _password);
CreateStructureAndData(connection);
}
//創建表及增加數據
CreateStructureAndData(connection);
//爲空是表示有錯誤
if (connection != null)
{
ModifyConfig();
}
//關閉數據庫
CloseConnection(connection);
}
/// <summary>
/// 關閉數據庫
/// </summary>
/// <param name="connection"></param>
private void CloseConnection(SqlConnection connection)
{
if (connection != null)
{
//關閉數據庫
if (connection.State != System.Data.ConnectionState.Closed)
{
connection.Close();
connection.Dispose();
}
}
}
/// <summary>
/// 測試連接
/// </summary>
/// <param name="serverName"></param>
/// <param name="dbName"></param>
/// <param name="userName"></param>
/// <param name="password"></param>
private SqlConnection TestConnection(string serverName, string dbName, string userName, string password)
{
string connectionString = GetConnectionString(serverName, dbName, userName, password);
SqlConnection connection = new SqlConnection(connectionString);
try
{
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
return connection;
}
catch
{
CloseConnection(connection);
throw new InstallException("安裝失敗!/n數據庫配置有誤,請正確配置信息!");
}
}
/// <summary>
/// 得到連接字符串
/// </summary>
/// <param name="serverName"></param>
/// <param name="dbName"></param>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <returns></returns>
private string GetConnectionString(string serverName, string dbName, string userName, string password)
{
string connectionString = "Data Source={0};Initial Catalog={1};User ID={2};Password={3}";
connectionString = string.Format(connectionString, serverName, dbName, userName, password);
return connectionString;
}
/// <summary>
/// 創建數據庫
/// </summary>
/// <param name="serverName"></param>
/// <param name="dbName"></param>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <param name="connection"></param>
/// <param name="stateSaver"></param>
public int CreateDataBase(SqlConnection connection)
{
int result = -1;
connection.ChangeDatabase("master");
string createDBSql = @" if Exists(select 1 from sysdatabases where [name]=N'{0}')
begin
drop database {0}
end
GO
CREATE DATABASE {0} ";
createDBSql = string.Format(createDBSql, _dbName);
string[] sqlList = createDBSql.Split(split);
SqlCommand command = null;
try
{
command = connection.CreateCommand();
command.CommandType = System.Data.CommandType.Text;
foreach (string sqlItem in sqlList)
{
if (sqlItem.Length > 2)
{
command.CommandText = sqlItem;
result = command.ExecuteNonQuery();
}
}
return result;
}
catch
{
CloseConnection(connection);
command.Dispose();
throw new InstallException("安裝失敗!/n數據庫配置不正確!");
}
}
/// <summary>
/// 分隔SQL語句
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
private string[] splitSql(string sql)
{
Regex regex = new Regex("^GO", RegexOptions.IgnoreCase | RegexOptions.Multiline);
string[] sqlList = regex.Split(sql.ToUpper());
return sqlList;
}
/// <summary>
/// 創建表結構及數據
/// </summary>
/// <param name="connection"></param>
public void CreateStructureAndData(SqlConnection connection)
{
StringBuilder builder = new StringBuilder();
SqlCommand command = null;
//錯誤標誌
bool isHaveError = false;
try
{
ResourceManager manager = new ResourceManager(typeof(YXSchoolSetupService.Properties.Resources));
if (manager != null)
{
connection.ChangeDatabase(_dbName);
command = connection.CreateCommand();
command.CommandType = CommandType.Text;
builder.Append(manager.GetString(_StructureAndDataFileName));
string[] sqlList = splitSql(builder.ToString());
foreach (string sqlItem in sqlList)
{
if (sqlItem.Length > 2)
{
command.CommandText = sqlItem;
command.ExecuteNonQuery();
}
}
}
else
{
isHaveError = true;
}
if (true == isHaveError)
{
CloseConnection(connection);
command.Dispose();
throw new InstallException("數據庫配置失敗!/n請與開發人員聯繫!");
}
}
catch
{
CloseConnection(connection);
command.Dispose();
throw new InstallException("數據庫配置失敗!/n請與開發人員聯繫!");
}
}
#region 修改web.config的連接數據庫的字符串
public void ModifyConfig()
{
System.IO.FileInfo FileInfo = new System.IO.FileInfo(_targetDir + "YXData.yixian");
if (!FileInfo.Exists) //不存在web.config文件
{
throw new InstallException("沒有找到文統配置文件!");
}
System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();
xmlDocument.Load(FileInfo.FullName);
try
{
XmlElement element = xmlDocument.DocumentElement;
if (element != null)
{
foreach (XmlNode node in element)
{
switch (node.Name)
{
case "dbserver":
node.InnerText = _serverName;
break;
case "dbname":
node.InnerText = _dbName;
break;
case "dbpassword":
node.InnerText = _password;
break;
case "dbuser":
node.InnerText = _userName;
break;
default:
break;
}
}
}
xmlDocument.Save(FileInfo.FullName);
}
catch
{
throw new InstallException("修改web.config配置文件失敗!");
}
}
#endregion
數據據庫測試界面中的代碼:
/// 連接測試是否成功
/// </summary>
public bool isConnect { get; set; }
private void frmDb_Load(object sender, EventArgs e)
{
btnNext.Enabled = false;
this.CenterToParent();
}
private void btnTest_Click(object sender, EventArgs e)
{ //將得到配置值傳給主安裝程序類
string serverName = txbServer.Text.Trim();
DBInstaller._serverName = serverName;
string dbName = txbDbName.Text.Trim();
DBInstaller._dbName = dbName;
string userName = txbUserName.Text.Trim();
DBInstaller._userName = userName;
string password = txbPwd.Text.Trim();
DBInstaller._password = password;
isConnect = InstallCommon.TestConnection(serverName, dbName, userName, password);//測試連接,此處調用其它類中的代碼。
if (isConnect == true)
{
lblInfo.Text = "數據庫連接測試成功!";
btnNext.Enabled = true;
}
else
{
btnNext.Enabled = false;
lblInfo.Text = "數據庫連接測試失敗!";
}
}
//取消按鈕
private void btnCancel_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.No;
this.Close();
}
//下一步按鈕
private void btnNext_Click(object sender, EventArgs e)
{
if (isConnect)
{
this.DialogResult = DialogResult.OK;
}
this.Close();
}