最近在做一個windows服務的項目,發現並解決了一些問題,拿出來和大家分享一下,以下windows服務簡稱“服務”
文章會在適合時間更新,因為朋友們在不斷提出新的意見或思路,感謝~。~
1.服務如何在某種情況下彈出一個窗體?
第一種解決辦法,用安裝程序的代碼修改注冊表來完成:
1.右擊服務的視圖設計界面的空白處,添加安裝程序
2.右擊默認的serviceProcessInstaller1-->屬性-->Account屬性設置為LocalSystem
3.右擊安裝程序空白處-->查看代碼,添加以下代碼
public override void Install(IDictionary stateServer) { Microsoft.Win32.RegistryKey system, currentControlSet,services, service, config; try { base.Install(stateServer); //打開注冊表值 system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System"); currentControlSet = system.OpenSubKey("CurrentControlSet"); services = currentControlSet.OpenSubKey("Services"); service = services.OpenSubKey(this.serviceInstaller1.ServiceName, true); //設置服務的描述 service.SetValue("Description", "這是一個服務"); //允許服務與桌面交互 int value = (int)service.GetValue("Type"); service.SetValue("Type", value | 256); config = service.CreateSubKey("Parameters"); } catch (Exception e) { Console.WriteLine("An exception was thrown during service installation:/n" + e.ToString()); } } public override void Uninstall(IDictionary stateServer) { Microsoft.Win32.RegistryKey system, currentControlSet, services, service; try { //Drill down to the service key and open it with write permission system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System"); currentControlSet = system.OpenSubKey("CurrentControlSet"); services = currentControlSet.OpenSubKey("Services"); service = services.OpenSubKey(this.serviceInstaller1.ServiceName, true); //Delete any keys you created during installation (or that your service created) service.DeleteSubKeyTree("Parameters"); //... } catch (Exception e) { Console.WriteLine("Exception encountered while uninstalling service:/n" + e.ToString()); } finally { //Let the project installer do its job base.Uninstall(stateServer); } }
這個方法很多,也可以在網上搜到
第二種解決辦法,用bat批處理文件修改注冊表完成(如果已經運行的服務不是LocalSystem賬戶,是不允許與桌面交互的)
創建一個bat文件,寫入以下代碼,保存並雙擊運行,點擊 y 回車更改服務賬戶
reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\自己服務的名稱/v ObjectName /t REG_SZ /d LocalSystem
如果想直接修改注冊表,在以上代碼前加"echo y|" (沒有雙引號) 這樣雙擊運行的時候就可以直接修改了
第三種解決辦法也是最簡單的辦法,通過手動修改
打開服務控制器,右擊要修改賬戶的服務屬性,登錄選項卡,修改為本地系統賬戶,並允許與桌面交互
2.服務如何獲取程序當前的路徑?
服務中使用Environment.CurrentDirectory獲取的是system32的路徑
解決辦法:添加引用:window.form
使用Application.StartupPath(獲取到程序生成的文件夾)
(其它方法暫時還沒有嘗試,所以先不寫了)
3.如何使用Timer?
和form不同,服務有專門的Timer
右擊工具箱"選擇項",.netFrameWork組件:找到Timer
別搞成Form里的Timer
4服務的更新
服務有時候出了問題也會用到更新,安裝服務機子少時候可以自己手動更新,多的話,像上百台或更多,在做需求的時候就要想到更新程序是如此的重要
我就是在這方面吃了大虧,請朋友們引以為戒
如兩個服務A和B,B是某某服務,A是B的更新服務,想要實現的功能:系統啟動時自動啟動A服務來檢測B服務是否有更新文件,有則下載更新,啟動B服務,無則直接啟動B服務
1.兩個服務一定要分開兩個項目來寫,如果在一個項目里寫兩個服務,在更新的時候就會提示程序正在訪問無法運行而更新失敗
2.B服務要設置為手動啟動,如果早與A服務自動啟動。並且A服務檢測到有更新文件,將無法完成B服務的更新
3.B服務設置為手動啟動,並不是讓你手動去啟動B服務。是通過A來啟動B。
啟動方式如下:
條件:B服務為LocalSystem,並且B服務已經安裝完成
利用進程啟動B服務
public void RunService() { Process PortProcess = new Process(); PortProcess.StartInfo.FileName = "cmd.exe"; PortProcess.StartInfo.UseShellExecute = false; PortProcess.StartInfo.RedirectStandardInput = true; PortProcess.StartInfo.RedirectStandardOutput = true; PortProcess.StartInfo.RedirectStandardError = true; PortProcess.StartInfo.CreateNoWindow = true; try { PortProcess.Start(); PortProcess.StandardInput.WriteLine("net start 服務的名稱"); PortProcess.StandardInput.WriteLine("exit"); PortProcess.Close(); } catch (Exception) { } }
其它方式有待改進,暫不貼出
5服務的調試
個人知道的有兩種服務調試的方式
1是用VS,附加到進程來做調試,步驟比較簡單但也有缺點
(1)安裝和啟動一個服務以后,點擊VS中的調試-->附加到進程(注意選擇"附加到"這個選項,一定要是自己程序的代碼,我用的.net4.0,所以我選擇的是"托管4.0版代碼")
(2)找到自己的程序進程,附加即可
這種方式的缺點:因為是在啟動以后才可以附加到進程.服務的OnStart方法無法調試。所以我一般都會把代碼放到OnStop方法里調試
2是做調試日志,每個步驟寫日志的方式來檢測服務是否正常啟動等(我一直沒用過,暫無介紹)不過個人認為這種方式也會有缺點.沒有斷點調試那樣直觀
不過有機會可以試試這種方式
多說都是淚,方法和思路都是自己試出來的,有什么代碼或思路錯誤請朋友們提出,對的點個贊,謝謝~
感謝區:
由於不知道怎么把評論人的名字搞到這里來,所以只能這樣感謝你們提出的意見了,謝謝~.~