这里仅简单记录一下,自己备忘。至于能否给大家参考,请大家自行阅读。
需求:
1.目前有一个WinForm程序,需要制作安装部署程序
2.需要添加一个Windows服务用于监控Winform程序的进程,防止退出,并且在Winform的安装部署程序中也要安装此服务。
解决方法:
WinForm的Project就不说了。
Windows服务程序的添加和ProjectInstaller的添加
- 在sln下面新建一个Window服务程序,在Winfows服务是Service1的设计界面点击右键“添加安装程序”,添加一个ProjectInstaller
- ProjectInstaller部分代码如下,在相应方法内写自定义操作的相关代码
public partial class ProjectInstaller : System.Configuration.Install.Installer { public ProjectInstaller() { InitializeComponent(); this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic;//设置服务为自动启动 this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalService;//设置服务安装指定的账号为本地系统 writeLog("xxxWindowsService ProjectInstaller run."); } public override void Install(System.Collections.IDictionary stateSaver) { base.Install(stateSaver); } protected override void OnAfterInstall(IDictionary savedState) { base.OnAfterInstall(savedState); writeLog("enter OnAfterInstall "); writeLog("leave OnAfterInstall "); } protected override void OnBeforeUninstall(IDictionary savedState) { base.OnBeforeUninstall(savedState); writeLog("enter OnBeforeUninstall "); writeLog("leave OnBeforeUninstall "); }
安装项目的添加
sln右键添加新建项目-其他项目类型-安装和部署-Visual Studio Installer-安装项目。
在解决方案资源管理器点击Setup1,再点击vs2010工具栏的属性图标(ctrl+w,p),在弹出的属性框内设置Setup项目的相关属性,包括Auther,Manufacturer,productName等属性。
在解决方案资源管理器点击Setup1,再点击vs2010工具栏的属性图标(ctrl+w,p),在左侧设计界面弹出文件系统编辑器,点击应用程序文件夹,在中间窗口右键添加项目输出,添加安装程序所需的相关dll等文件。这里不再详细说具体的步骤了,网上baidu,google一大把。
现在说添加安装windows服务:
- 在文件系统编辑器中添加Window服务项目作为主输出后,Setup项目生成Setup文件安装时就会自动在安装Winform程序的时候安装Windows服务。
- 下面是如何在安装WindowsService过程中获取自定义参数的配置。
- 在解决方案资源管理器点击Setup1,再点击解决方案资源管理器顶部的自定义操作编辑器图标。
- 在自定义操作编辑器设计区域右键点击“安装”添加项目输出(这个项目输出要选中Windows服务那个项目)。
- 选中刚刚添加的项目输出,右键属性窗口,设置CustomActionData值为 /TARGETDIR="[TARGETDIR]\",注意,这里设置这个参数目的是能在Windows服务中的ProjectInstaller的方法中能获取到用户在安装过程中选中的安装程序路径。在ProjectInstaller中的OnAfterInstall方法中通过代码Context.Parameters.ContainsKey("TARGETDIR")获取到用户在安装过程中选中的安装程序路径。
- 右键点击“卸载”添加项目输出(这个项目输出要选中Windows服务那个项目)。重复上一步的操作设置属性相应值。
完整ProjectInstaller的代码如下:
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
private string softWareMainFolder = "xxxMain";//Setup程序中配置的应用程序文件内自定义的主程序文件夹名
private string softWareServiceFolder = "xxxService";//Setup程序中配置的应用程序文件内自定义的服务程序文件夹名
private string serviceName = "xxxWinService";//服务名称
public ProjectInstaller()
{
InitializeComponent();
this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic;//设置服务为自动启动
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;//设置服务安装指定的账号为本地系统
writeLog(Environment.NewLine);//添加换行便于日志查看
writeLog("xxxWindowsService ProjectInstaller run.");
}
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
}
protected override void OnAfterInstall(IDictionary savedState)
{
base.OnAfterInstall(savedState);
//安装成功后更改服务配置文件中的被监控程序的路径
try
{
writeLog("enter OnAfterInstall ");
#region 测试自定义参数
writeLog("Context.Parameters.Keys.Count= " + Context.Parameters.Keys.Count.ToString());
StringBuilder keysValues = new StringBuilder(string.Empty);
foreach (string s in Context.Parameters.Keys)
{
if (keysValues.Length > 0)
{
keysValues.Append(",");
keysValues.Append(Environment.NewLine);
}
keysValues.Append(s);
keysValues.Append("=");
string v = Context.Parameters[s];
keysValues.Append(v);
}
writeLog("Context.Parameters.Keys-Values:" + keysValues);
if (Context.Parameters.Keys.Count <= 0)
{
writeLog("Context.Parameters.Keys.Count <= 0, OnAfterInstall exit");
return;
}
if (Context.Parameters.ContainsKey("TARGETDIR") == false)
{
writeLog("Context.Parameters.ContainsKey(TARGETDIR) == false, OnAfterInstall exit");
return;
}
#endregion
#region 更改服务exe.config中守护的主程序地址
var map = new ExeConfigurationFileMap();
writeLog("Context.Parameters[TARGETDIR]=" + Context.Parameters["TARGETDIR"]);
string path = Context.Parameters["TARGETDIR"];
writeLog("old TARGETDIR=" + path);
path = path.Replace(@"\\", @"\");
writeLog("new TARGETDIR=" + path);
//Get app.config path
map.ExeConfigFilename = path + softWareServiceFolder + @"\xxxWindowsService.exe.config";
writeLog("map.ExeConfigFilename=" + map.ExeConfigFilename);
//Get Config and AppSettings
var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
var appSettings = config.AppSettings;
//Get input value from setup project
//var configValueList = new List<string>() { Context.Parameters["Config1"],
// Context.Parameters["Config2"],
// Context.Parameters["Config3"] };
string cpsExePath = path + softWareMainFolder + @"\xxx.exe";
writeLog("appSettings.Settings[Watch_Process1].Value=" + appSettings.Settings["Watch_Process1"].Value);
writeLog("new dir=" + cpsExePath);
//assign input value to appSettings
appSettings.Settings["Watch_Process1"].Value = cpsExePath;
int SessionID = GetExplorerProcessSessionID();
appSettings.Settings["SessionId"].Value = SessionID.ToString();
//save app.config
config.Save();
#endregion
//注意这里只需添加启动服务的代码即可,无需添加安装服务的代码因为安装服务的功能在安装程序的自定义界面中已定义
#if useBatStartOrStop
#region 执行启动服务
string installbatPath = path + softWareServiceFolder + @"\startService.bat";
RunBat(installbatPath);
#endregion
#else
StartService(serviceName);//用C#的方式启动服务
#endif
writeLog("leave OnAfterInstall ");
}
catch (Exception e)
{
writeLog(e.Message);
}
}
protected override void OnBeforeUninstall(IDictionary savedState)
{
base.OnBeforeUninstall(savedState);
//卸载前先停止服务
try
{
writeLog("enter OnBeforeUninstall ");
//#region 测试自定义参数
//writeLog("Context.Parameters.Keys.Count= " + Context.Parameters.Keys.Count.ToString());
//StringBuilder keysValues = new StringBuilder(string.Empty);
//foreach (string s in Context.Parameters.Keys)
//{
// keysValues.Append(s);
// keysValues.Append("=");
// string v = Context.Parameters[s];
// keysValues.Append(v);
// keysValues.Append(",");
// keysValues.Append(Environment.NewLine);
//}
//writeLog("Context.Parameters.Keys-Values:" + keysValues);
//if (Context.Parameters.ContainsKey("TARGETDIR") == false)
//{
// writeLog("Context.Parameters.ContainsKey(TARGETDIR) == false, OnAfterInstall exit");
// return;
//}
//#endregion
//writeLog("Context.Parameters[TARGETDIR]=" + Context.Parameters["TARGETDIR"]);
//string path = Context.Parameters["TARGETDIR"];
//writeLog("old TARGETDIR=" + path);
//path = path.Replace(@"\\", @"\");
//writeLog("new TARGETDIR=" + path);
//注意这里只需添加停止服务的代码即可,无需添加删除服务的代码因为删除服务的功能在安装程序的自定义界面中已定义
#if useBatStartOrStop
#region 执行bat停止服务
writeLog("start StopService");
string stopServicebatPath = path + softWareServiceFolder + @"\stopService.bat";
RunBat(stopServicebatPath);
writeLog("end StopService");
#endregion
#else
StopService(serviceName);//用C#方式停止服务
#endif
#region 结束进程
writeLog("start kill xxx.exe ");
KillProcess("xxx");//StopProcess("KmisToVams");//根据进程名结束进程
writeLog("end kill xxx.exe");
#endregion
//#region 执行bat卸载服务
//string uninstallbatPath = path + @"cpsServiceWatch\uninstall.bat";
//RunBat(uninstallbatPath);
//#endregion
writeLog("leave OnBeforeUninstall ");
}
catch (Exception ex)
{
writeLog(ex.Message);
}
}
//执行批处理文件
private void RunBat(string batPath)
{
writeLog("enter RunBat run" + batPath);
Process pro = new Process();
FileInfo file = new FileInfo(batPath);
pro.StartInfo.WorkingDirectory = file.Directory.FullName;
pro.StartInfo.FileName = batPath;
pro.StartInfo.CreateNoWindow = false;
pro.Start();
pro.WaitForExit();
writeLog("leave RunBat");
}
/// <summary>
/// 检查缓存文件存放的目录是否存在,如果不存在则创建。
/// </summary>
/// <param name="directoryPath"></param>
public void CheckDirectory(string directoryPath)
{
DirectoryInfo dInfo = new DirectoryInfo(directoryPath);
if (!dInfo.Exists)
{
dInfo.Create();
}
}
//记录安装日志,日志在C:\vams_install\vams_install_yyyyMMdd.log中
void writeLog(string msg)
{
string dir = @"C:\kmisToAei_install_logs\";
CheckDirectory(dir);
FileInfo fileLog = new FileInfo(dir + @"k2a_install_" + DateTime.Today.ToString("yyyyMMdd") + ".log");
FileStream fileStream = null;
StreamWriter swOld = null;
StreamWriter swNew = null;
string currentTime = string.Format("[{0}:{1,4:D}] ", DateTime.Now.ToString(), DateTime.Now.Millisecond);
try
{
//判断是否存在文件
if (fileLog.Exists)
{
fileStream = new FileStream(fileLog.FullName, FileMode.Append, FileAccess.Write);
//如果存在文件,则向文件添加日志
swOld = new StreamWriter(fileStream);
//swOld.WriteLine();
//swOld.WriteLine("============================================================================");
swOld.Write(currentTime + ":");
swOld.WriteLine(msg);
swOld.Flush();
swOld.Close();
}
else
{
fileStream = fileLog.Create();
//如果文件不存在,则创建文件后向文件添加日志
swNew = new StreamWriter(fileStream);
//swNew.WriteLine();
//swNew.WriteLine("============================================================================");
swNew.Write(currentTime + ":");
swNew.WriteLine(msg);
swNew.Flush();
swNew.Close();
}
}
catch
{
}
finally
{
if (fileStream != null)
{
fileStream.Close();
fileStream.Dispose();
}
if (swOld != null)
{
swOld.Close();
swOld.Dispose();
}
if (swNew != null)
{
swNew.Close();
swNew.Dispose();
}
}
}
private void KillProcess(string processName)
{
writeLog("enter KillProcess processName" + processName);
System.Diagnostics.Process myproc = new System.Diagnostics.Process();
//得到所有打开的进程
try
{
//#region 打印所有进程
//StringBuilder allproc = new StringBuilder();
//Process[] arrayProcess = Process.GetProcesses();
//foreach (Process p in arrayProcess)
//{
// allproc.AppendLine(p.Id + ":" + p.ProcessName);
//}
//writeLog("all process:" + allproc.ToString());
//#endregion
writeLog("processName[" + processName + "]count=" + Process.GetProcessesByName(processName).Length);
foreach (Process thisproc in Process.GetProcessesByName(processName))
{
////找到程序进程,kill之。
//if (!thisproc.CloseMainWindow())
//{
// thisproc.Kill();
//}
//找到程序进程先正常关闭,正常关闭失败时kill之。
bool closeUI = false;
for (int i = 0; i < 5; i++)
{
if (thisproc.CloseMainWindow())
{
closeUI = true;
}
else
{
System.Threading.Thread.Sleep(1000);//如果关闭窗口失败则循环5次尝试
}
}
writeLog("KillProcess closeUI=" + closeUI.ToString());
if (closeUI == false)
{
thisproc.Kill();
thisproc.WaitForExit(5000);
thisproc.Close();//清理资源
writeLog("KillProcess run kill ");
}
}
}
catch (Exception Exc)
{
//MessageBox.Show(Exc.Message);
writeLog(Exc.Message);
}
writeLog("leave KillProcess");
}
public void StopProcess(string processName)
{
writeLog("enter StopProcess");
try
{
System.Diagnostics.Process[] ps = System.Diagnostics.Process.GetProcessesByName(processName);
foreach (System.Diagnostics.Process p in ps)
{
p.CloseMainWindow();//关闭UI
System.Threading.Thread.Sleep(2000);
p.Kill();
p.WaitForExit(5000);
p.Close();//清理资源
}
}
catch (Exception ex)
{
KillProcess(processName);
//throw ex;
writeLog(ex.Message);
}
writeLog("leave StopProcess");
}
/// <summary>
/// 获取explorer.exe进程的SessionID
/// </summary>
/// <returns></returns>
public int GetExplorerProcessSessionID()
{
int sessionId = 0;
try
{
Process[] arrayProcess = Process.GetProcesses();
foreach (Process p in arrayProcess)
{
//System、Idle进程会拒绝访问其全路径
if (p.ProcessName.ToLower() == "explorer")
{
sessionId = p.SessionId;
writeLog("explorer sessionId=" + p.SessionId.ToString());
break;
}
}
}
catch { }
return sessionId;
}
#region 服务处理
#region 检查服务存在的存在性
/// <summary>
/// 检查服务存在的存在性
/// </summary>
/// <param name=" NameService ">服务名</param>
/// <returns>存在返回 true,否则返回 false;</returns>
public bool IsServiceIsExisted(string NameService)
{
ServiceController[] services = ServiceController.GetServices();
foreach (ServiceController s in services)
{
if (s.ServiceName.ToLower() == NameService.ToLower())
{
return true;
}
}
return false;
}
#endregion
#region 判断window服务是否启动
/// <summary>
/// 判断某个Windows服务是否启动
/// </summary>
/// <returns></returns>
public bool IsServiceStart(string serviceName)
{
ServiceController psc = new ServiceController(serviceName);
bool bStartStatus = false;
try
{
if (psc.Status.Equals(ServiceControllerStatus.Running)||
psc.Status.Equals(ServiceControllerStatus.ContinuePending)||
psc.Status.Equals(ServiceControllerStatus.StartPending)
)
{
bStartStatus = true;
}
return bStartStatus;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
#endregion
#region 启动服务
private void StartService(string serviceName)
{
if (IsServiceIsExisted(serviceName))
{
ServiceController sc = new ServiceController(serviceName);
if (sc.Status != ServiceControllerStatus.Running
&& sc.Status != ServiceControllerStatus.StartPending)
{
writeLog(string.Format("准备启动服务{0}", serviceName));
sc.Start();
writeLog(string.Format("正在启动服务{0}", serviceName));
sc.WaitForStatus(ServiceControllerStatus.Running);
writeLog(string.Format("已成功启动服务{0}", serviceName));
}
else
{
writeLog(string.Format("本次启动服务{0}的请求被取消,因为服务正在启动或已启动", serviceName));
}
}
else
{
writeLog(string.Format("服务{0}不存在,无法启动", serviceName));
}
}
#endregion
#region 停止服务
private void StopService(string serviceName)
{
if (IsServiceIsExisted(serviceName))
{
ServiceController sc = new ServiceController(serviceName);
if (sc.Status != ServiceControllerStatus.Stopped
&&sc.Status!=ServiceControllerStatus.StopPending)
{
writeLog(string.Format("准备停止服务{0}", serviceName));
sc.Stop();
writeLog(string.Format("正在停止服务{0}", serviceName));
sc.WaitForStatus(ServiceControllerStatus.Stopped);
writeLog(string.Format("已成功停止服务{0}", serviceName));
}
else
{
writeLog(string.Format("本次停止服务{0}的请求被取消,因为服务正在停止或已停止", serviceName));
}
}
else
{
writeLog(string.Format("服务{0}不存在,无法停止", serviceName));
}
}
#endregion
#endregion
}