Windows服務啓動exe無界面終極解決方案

摘自: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、收尾

  哈哈,這個方法怎麼樣。徹底麼?

 

 
好文要頂 關注我 收藏該文  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章