• Windows服务启动exe无界面终极解决方案


     

     

    1、前言

    我这个方案(C#操作)是彻底解决【从Windows服务启动程序exe,程序无界面】问题的终极解决方案,终极方案,绝对的终极方案。后附代码下载地址。

    由于安全性问题,Vista以后的Windows都会出现该问题,从服务中调用/启动其他程序出现无界面,但是任务管理器中可以看到已经成功启动,就是无操作界面,具体出现该状况的原因大家自行搜索。我的方法绝对可行。

    PS:服务是自己写的,要实现其他特殊功能,其他手法无法轻易绕过去。CSDN一点东西就要开VIP,那帮作者,呵呵,好东西还是在cnblogs里吧。

    简而言之,本文的应用场景是:服务必须自建,还要打开外部exe

    2、网上方案

    网上有各种各样的方案,绝大部分都有一样的,都是是调用系统API,CreateProcess之类的API,然并卵,并不能彻底解决。

    ***2023-07-03****补充***

    看到有人评价使用NSSM,我这服务是自己写的,因为它要实现其他特殊的功能,所以nssm什么的没有用哦,反而复杂了。

    ***2023-07-03****补充***

    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、收尾

      哈哈,这个方法怎么样。彻底么?

     

  • 相关阅读:
    Minio学习
    机器视觉常见的问题及解决
    【Linux】进程间通信
    文字验证码:简单有效的账号安全守卫!
    leetcode-495-提莫攻击
    一个程序员的成长之路
    计算机操作系统 (王道考研)笔记(四)I/O系统
    CentOS7部署Redis7集群
    23种设计模式之 : 模板方法设计模式
    软件设计师考试学习1
  • 原文地址:https://www.cnblogs.com/ZoeWong/p/17516579.html