摘自:https://www.cnblogs.com/ZoeWong/p/17516579.html
1、前言
我這個方案(C#操作)是徹底解決【從Windows服務啓動程序exe,程序無界面】問題的終極解決方案,終極方案,絕對的終極方案,本來打算收錢的,還是算了,你們也不容易,關注我一下就行。後附代碼下載地址。
由於安全性問題,Vista以後的Windows都會出現該問題,從服務中調用/啓動其他程序出現無界面,但是任務管理器中可以看到已經成功啓動,就是無操作界面,具體出現該狀況的原因大家自行搜索。我的方法絕對可行。
2、網上方案
網上有各種各樣的方案,絕大部分都有一樣的,都是是調用系統API,CreateProcess之類的API,然並卵,並不能徹底解決。
3、我的方案
我的方案極其簡單而不粗暴,反而優美。
3.1、簡單不粗暴
我的方案是使用計劃任務功能啓動指定程序。任務計劃的啓動不受服務限制,和服務的邊界不太一樣。不需要特別多的代碼就可以實現,其實就是實現添加任務計劃,簡單吧。API方式,光結構和調試就夠你們喝一壺了,還得通過其他API調用和設置其他信息,比如創建和複製現有執行令牌(DuplicateTokenEx方法),實現這功能粗暴得狠。我這個不用,啥都不用。
3.2、優美
創建任務寥寥十幾行代碼,優美得狠。
4、實現過程
實現過程即任務計劃實現過程,C#有3種方法,其實就是2種,一種是使用API創建任務,這個方法其實,可以通過系統調用現有dll庫實現,最後一種是使用開源庫。建議用開源庫方式。
調用系統的dll,這dll就是C:\Windows\System32\taskschd.dll,在C#裏直接引用就行,它實現API的C#封裝,很簡單。使用TaskSchedulerClass類連接、創建修改任務計劃,很簡單,我這不是主推方法,不貼代碼,但源碼地址裏有。
使用開源庫TaskScheduler,可以實現,命名空間爲Microsoft.Win32.TaskScheduler,下載地址爲:https://github.com/dahall/TaskScheduler。例子爲:https://github.com/dahall/TaskScheduler/wiki/Examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public static void AddOrRunWinTask( string sTaskName, string sExePath, string sArgs = null ) { var task = TaskService.Instance.FindTask(sTaskName, true ); if ( task != null ) { task.Definition.Triggers[0].StartBoundary = DateTime.Now.AddSeconds ( 10 ); task.RegisterChanges (); } else { var td = TaskService.Instance.NewTask (); td.RegistrationInfo.Author = "白羊佐CSDN" ; td.RegistrationInfo.Description = "用於跨域啓動特定程序" ; td.Settings.ExecutionTimeLimit = TimeSpan.Zero; // td.Settings.DisallowStartIfOnBatteries = false ; td.Settings.RunOnlyIfIdle = false ; td.Settings.RunOnlyIfNetworkAvailable = false ; //此處注意,如果你待啓動程序需要管理員權限運行,必須使用Highest,否則使用LUA就行 td.Principal.RunLevel = TaskRunLevel.Highest; //獲取Administrators的GroupID string sGpId = GetGroupID(); //此處最爲關鍵,如果不指定用戶名ID或組名ID,依舊不顯示界面,因爲創建時的用戶爲SYSTEM td.Principal.GroupId = sGpId; var trigger = (TimeTrigger)td.Triggers.Add( new TimeTrigger() ); trigger.StartBoundary = DateTime.Now.AddSeconds ( 10 ); trigger.ExecutionTimeLimit = TimeSpan.Zero; trigger.Enabled = true ; td.Actions.Add ( new ExecAction ( sExePath, sArgs ) ); task = TaskService.Instance.RootFolder.RegisterTaskDefinition ( sTaskName, td ); } //打開表示立即運行(切運行兩次,因爲上面有個執行延時) //var rz = task.Run (); } |
注意,注意,再注意:A、此方法是win10的,因爲win10默認屏蔽Administrator用戶,我用戶屬於這個組,所以我這個地方使用這種方式沒有問題。但是,其他非Administrators組用戶登錄可能不行了,那也好解決,將下面代碼中GroupPrincipal改爲UserPrincipal,用它去找登錄的用戶名,上面代碼設userid,logontype就行。或者輸入正確的組名都可以;B、此方式程序的啓動位置爲System32,你程序的目錄獲取時要注意了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private static string GetGroupID () { string sGid = null ; System.DirectoryServices.AccountManagement.PrincipalContext pc = new System.DirectoryServices.AccountManagement.PrincipalContext(System.DirectoryServices.AccountManagement.ContextType.Machine); var identity = System.DirectoryServices.AccountManagement.GroupPrincipal.FindByIdentity(pc, "Administrators" ); if ( identity != null ) { sGid = identity.Sid.Value; } return sGid; } |
5、工具及代碼下載地址
https://files.cnblogs.com/files/ZoeWong/TaskScheduler.2.10.1%E5%8C%85.rar?t=1688102826&download=true
6、收尾
哈哈,這個方法怎麼樣。徹底麼?