windows服务 - C# U盘升级
1.左侧工具栏里有Timer控件,但是如果调用的是系统时间,就需要添加System.timer.timer空间下的控件。
2.服务编写之后,还不能由SCM(服务控制管理器)进行管理,需要给该服务添加装载器。在Service1.cs的设计视图,点击右键,选择“添加装载器”,系统默认就会添加ProjectInstaller.cs这个类
添加该类后,在该类的设计视图上可看到serviceInstaller1和serviceProcessInstaller1,分别设置其属性。
设置serviceInstaller1的运行方式为手动或者自动
设置serviceInstaller1的ServiceName,设置为什么,服务列表中就显示什么
设置serviceProcessInstaller1的运行账号为LocalSystem
3.用U盘实现自动升级软件
步骤:
1.软件打包zip
2.读取U盘 复制到指定位置
3.关闭软件 解压到指定位置
4.启动软件 删除zip
3.1 解压缩 (难点)
1.下载SharpZipLib.dll ,添加引用,添加一个解压类 UnZipClass.cs
UnZipClass.cs
UnZipClass.cs /// <summary> /// 解压文件 /// </summary> using System; using System.Text; using System.Collections; using System.IO; using System.Diagnostics; using System.Runtime.Serialization.Formatters.Binary; using System.Data; using ICSharpCode.SharpZipLib.BZip2; using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Zip.Compression; using ICSharpCode.SharpZipLib.Zip.Compression.Streams; using ICSharpCode.SharpZipLib.GZip; namespace TestWinform { public class UnZipClass { public void UnZip(string[] args) { ZipInputStream s = new ZipInputStream(File.OpenRead(args[0])); ZipEntry theEntry; while ((theEntry = s.GetNextEntry()) != null) { string directoryName = Path.GetDirectoryName(args[1]); string fileName = Path.GetFileName(theEntry.Name); //生成解压目录 Directory.CreateDirectory(directoryName); if (fileName != String.Empty) { //解压文件到指定的目录 FileStream streamWriter = File.Create(args[1] + theEntry.Name); int size = 2048; byte[] data = new byte[2048]; while (true) { size = s.Read(data, 0, data.Length); if (size > 0) { streamWriter.Write(data, 0, size); } else { break; } } streamWriter.Close(); } } s.Close(); } } }
3.2 (启动进程难点)
因为启动进程的用户名是System,开启进程后,不会显示exe的界面,所以必须 【模拟用户开启进程】,调用方法
//模拟用户开启进程
SystemUser.CreateProcess(SystemUser.WTSGetActiveConsoleSessionId(), filePath, "");
SystemUser.cs
SystemUser.cs using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Security.Principal; using System.Text; namespace SupervisionWindowsService { class SystemUser { #region 获取/复制用户令牌,启动进程 internal const int GENERIC_ALL_ACCESS = 0x10000000; //访问权限 [StructLayout(LayoutKind.Sequential)] public struct StartUpInfo { public Int32 cb; public string lpReserved; public string lpDesktop; public string lpTitle; public Int32 dwX; public Int32 dwY; public Int32 dwXSize; public Int32 dwXCountChars; public Int32 dwYCountChars; public Int32 dwFillAttribute; public Int32 dwFlags; public Int16 wShowWindow; public Int16 cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] public struct Process_Information { public IntPtr hProcess; public IntPtr hThread; public Int32 dwProcessID; public Int32 dwThreadID; } [StructLayout(LayoutKind.Sequential)] public struct SecurityAttributes { public Int32 Length; public IntPtr lpSecurityDescriptor; public bool bInheritHandle; } public enum SecurityImpersonationLevel { SecurityAnonymous, SecurityIdentification, SecurityImpersonation, SecurityDelegation } public enum TokenType { TokenPrimary = 1, TokenImpersonation } [DllImport("advapi32", SetLastError = true)] public static extern bool OpenProcessToken(IntPtr processHandle, TokenAccessLevels desiredAccess, ref IntPtr htok); [DllImport("advapi32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)] public static extern bool CreateProcessAsUser( IntPtr hToken, string lpApplicationName, string lpCommandLine, ref SecurityAttributes lpProcessAttributes, ref SecurityAttributes lpThreadAttributes, bool bInheritHandle, Int32 dwCreationFlags, IntPtr lpEnvrionment, string lpCurrentDirectory, ref StartUpInfo lpStartupInfo, ref Process_Information lpProcessInformation); [DllImport("advapi32.dll", SetLastError = true)] public static extern bool DuplicateTokenEx( IntPtr hExistingToken, Int32 dwDesiredAccess, ref SecurityAttributes lpThreadAttributes, Int32 ImpersonationLevel, Int32 dwTokenType, ref IntPtr phNewToken); [DllImport("userenv.dll", SetLastError = true)] public static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit); [DllImport("kernel32.dll")] public static extern int WTSGetActiveConsoleSessionId(); [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool CloseHandle(IntPtr handle); #endregion #region 模拟用户进程 /// <summary> /// 调用方必须具备System权限 /// </summary> /// <param name="sessionId"></param> /// <param name="appFullName"></param> /// <param name="args"></param> public static void CreateProcess(int sessionId, string appFullName, string args) { if (!System.IO.File.Exists(appFullName)) { throw new System.IO.FileNotFoundException(appFullName); } bool sucess = false; IntPtr hToken = IntPtr.Zero, hDupedToken = IntPtr.Zero; Process_Information pi = new Process_Information(); SecurityAttributes sa; try { //服务程序中,通过桌面进程的SessionId来获得 Process explorer = null; foreach (var process in Process.GetProcessesByName("explorer")) { if (process.SessionId == sessionId) { explorer = process; break; } } if (explorer == null) { TraceWin32Error("There has no Explorer process running yet!"); return; } Process.EnterDebugMode(); sucess = OpenProcessToken(explorer.Handle, TokenAccessLevels.Duplicate | TokenAccessLevels.Read | TokenAccessLevels.Impersonate, ref hToken); if (!sucess) { TraceWin32Error("OpenProcessToken"); return; } sa = new SecurityAttributes(); sa.Length = Marshal.SizeOf(sa); var si = new StartUpInfo(); si.cb = Marshal.SizeOf(si); sucess = DuplicateTokenEx( hToken, GENERIC_ALL_ACCESS, ref sa, (int)SecurityImpersonationLevel.SecurityIdentification, (int)TokenType.TokenPrimary, ref hDupedToken ); if (!sucess) { TraceWin32Error("DuplicateTokenEx"); return; } IntPtr lpEnvironment = IntPtr.Zero; sucess = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false); if (!sucess) { TraceWin32Error("CreateEnvironmentBlock"); return; } sucess = CreateProcessAsUser( hDupedToken, appFullName, args, ref sa, ref sa, false, 0, IntPtr.Zero, null, ref si, ref pi ); if (!sucess) { TraceWin32Error("CreateProcessAsUser"); } } finally { if (hDupedToken != IntPtr.Zero) CloseHandle(hDupedToken); if (pi.hProcess != IntPtr.Zero) CloseHandle(pi.hProcess); if (pi.hThread != IntPtr.Zero) CloseHandle(pi.hThread); Process.LeaveDebugMode(); } } static void TraceWin32Error(string error) { //WriteLog("{0}\t{1}:Last Error Code[{2}]", DateTime.Now.ToString(), error, Marshal.GetLastWin32Error().ToString()); } #endregion } }
3.3 获取当前工作目录(安装路径)
开始的情况这么写是错误的。
//获取当前工作目录
//string CurrentDirectoryPath = Environment.CurrentDirectory + \\Debug.zip;
/*
Windows服务在系统安装后会在注册表的 "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\[ServiceName]"下以服务的ServiceName建1个目录,目录中会有"ImagePath"节,这里保存的就是该服务的安装路径。
*/
//获取注册表的ImagePath路径 public static string GetWindowsServiceInstallPath(string ServiceName) { string key = "SYSTEM\\CurrentControlSet\\Services\\" + ServiceName; string path = Registry.LocalMachine.OpenSubKey(key).GetValue("ImagePath").ToString(); path = path.Substring(0, path.LastIndexOf("\\")); return path; }
3.4 开启关闭进程辅助类
MyProcess.cs
MyProcess.cs using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; namespace TestWinform { class MyProcess { /// <summary> /// 得到进程名 /// </summary> /// <param name="ProcName"></param> /// <returns></returns> public static bool getcloseProc(string ProcName) { bool result = false; System.Collections.ArrayList procList = new System.Collections.ArrayList(); string tempName = ""; int begpos; int endpos; foreach (System.Diagnostics.Process thisProc in System.Diagnostics.Process.GetProcesses()) { tempName = thisProc.ToString(); begpos = tempName.IndexOf("(") + 1; endpos = tempName.IndexOf(")"); tempName = tempName.Substring(begpos, endpos - begpos); procList.Add(tempName); if (tempName == ProcName) { result = true; } } return result; } /// <summary> /// 关闭进程 /// </summary> /// <param name="ProcName"></param> /// <returns></returns> public static bool closeProc(string ProcName) { bool result = false; System.Collections.ArrayList procList = new System.Collections.ArrayList(); string tempName = ""; int begpos; int endpos; foreach (System.Diagnostics.Process thisProc in System.Diagnostics.Process.GetProcesses()) { tempName = thisProc.ToString(); begpos = tempName.IndexOf("(") + 1; endpos = tempName.IndexOf(")"); tempName = tempName.Substring(begpos, endpos - begpos); procList.Add(tempName); if (tempName == ProcName) { if (!thisProc.CloseMainWindow()) thisProc.Kill(); //当发送关闭窗口命令无效时强行结束进程 result = true; } } return result; } /// <summary> /// 开启进程(这个方法只能开启用户名为System) /// </summary> /// <param name="ppath"></param> public static void MyProcessStart(string ppath) { Process MyProcess = new Process(); MyProcess.StartInfo.FileName = ppath; MyProcess.StartInfo.Verb = "Open"; MyProcess.StartInfo.CreateNoWindow = true; MyProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized; MyProcess.Start(); } } }
4.Service1.cs
Service1.cs
Service1.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.IO; using System.Linq; using System.ServiceProcess; using System.Text; using System.Threading; using System.Windows.Forms; using Microsoft.Win32; using SupervisionWindowsService; using TestWinform; namespace WindowsServiceDemo { public partial class Service1 : ServiceBase { static bool auto = true; public Service1() { InitializeComponent(); } protected override void OnStart(string[] args) { timer1.Enabled = true; timer1.Start(); } protected override void OnStop() { timer1.Stop(); timer1.Enabled = false; } static void print(DriveInfo di) { Console.WriteLine("可移动磁盘为" + di.Name); if (di.IsReady) { //path U盘根目录 string path = di.RootDirectory.ToString(); //pathNext U盘根目录下的Debug.zip string pathNext = path + "Debug.zip"; //判断是U盘是否存在debug.zip if (File.Exists(pathNext)) { //获取当前工作目录 //string CurrentDirectoryPath = Environment.CurrentDirectory + "\\Debug.zip"; string CurrentDirectoryPath = GetWindowsServiceInstallPath("SupervisionWindowsService") + "\\Debug.zip"; //如果存在则删除 if (File.Exists(CurrentDirectoryPath)) { File.Delete(CurrentDirectoryPath); } try { //(1)复制到本地目录 File.Copy(pathNext, CurrentDirectoryPath); ////(2)关闭进程TestForm if (MyProcess.getcloseProc("TestWinform")) { MyProcess.closeProc("TestWinform"); } //(解压)2.SharpZipLib.dll - 解压 string[] FileProperties = new string[2]; FileProperties[0] = CurrentDirectoryPath;//待解压的文件 FileProperties[1] = GetWindowsServiceInstallPath("SupervisionWindowsService") + "\\";//解压后放置的目标目录 UnZipClass UnZc = new UnZipClass(); UnZc.UnZip(FileProperties); } catch (Exception ex) { Debug.WriteLine(ex.Message); } } //(3)开启进程 //readPool.QueueUserWorkItem(DialUpAuto); string filePath = GetWindowsServiceInstallPath("SupervisionWindowsService") + "\\TestWinform.exe"; //string aimPath = filePath + "\\"; //string toPath = Path.Combine(aimPath, "TestOver.exe"); if (!MyProcess.getcloseProc("TestWinform")) { //模拟用户开启进程 SystemUser.CreateProcess(SystemUser.WTSGetActiveConsoleSessionId(), filePath, ""); //MyProcess.MyProcessStart(filePath); } } } //获取注册表的ImagePath路径 public static string GetWindowsServiceInstallPath(string ServiceName) { string key = "SYSTEM\\CurrentControlSet\\Services\\" + ServiceName; string path = Registry.LocalMachine.OpenSubKey(key).GetValue("ImagePath").ToString(); path = path.Substring(0, path.LastIndexOf("\\")); return path; } private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { timer1.Interval = 30000; DriveInfo[] dr = DriveInfo.GetDrives(); foreach (DriveInfo di in dr) { if (di.DriveType == DriveType.Removable) { print(di); } else if (di.DriveType == DriveType.Fixed) { Debug.WriteLine("{0}是本地磁盘。", di.Name); } } } } }