windows服务程序启动外部exe程序

       目的是service中检查某个exe是否运行了,没有则启动程序。

       启动的程序有界面。网上不少是使用ShellExecute来实现的,发现有问题,在win7下实现之后,service启动该程序时会出现一个提示,点击查看会切换到一个奇怪的界面来运行程序。这是因为已经调到session0了,如下图所示:

                    

        出现这个现象的原因是:

        在Windows XP、Windows Server 2003 或早期Windows 系统时代,当第一个用户登录系统后服务和应用程序是在同一个Session 中运行的。但是这种运行方式提高了系统安全风险,因为服务是通过提升了用户权限运行的,而应用程序往往是那些不具备管理员身份的普通用户运行的,其中的危险显而易见。 从Vista 开始Session 0 中只包含系统服务,其他应用程序则通过分离的Session 运行,将服务与应用程序隔离提高系统的安全性。如下图所示:

                                  

        这样使得Session 0 与其他Session 之间无法进行交互,不能通过服务向桌面用户弹出信息窗口、UI 窗口等信息。所以会弹出那个窗口。

        所以ShellExecute适用于Vista之前的系统。Vista之后,则需要穿过session隔离来启动一个程序。方法是取得当前Session Id,然后以此id创建令牌,再调用CreateProcessAsUser以当前用户来启动程序。

       代码示例如下:

     

BOOL bSuccess = TRUE;
        DWORD dwSessionId = WTSGetActiveConsoleSessionId();
        if(dwSessionId == 0xFFFFFFFF)
        {
            bSuccess = FALSE;
            //logger->TraceInfo("no active console session");
            continue;
        }


        HANDLE hToken = NULL;
        if(!WTSQueryUserToken(dwSessionId,&hToken))
        {
            bSuccess = FALSE;
            //logger->TraceInfo("WTSQueryUserToken erong %d",GetLastError());
            continue;
        }


        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        ZeroMemory(&si,sizeof(STARTUPINFO));
        ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));
        si.cb = sizeof(STARTUPINFO);
        wchar_t desktopName[] = L"WinSta0\\Default";
        si.lpDesktop = desktopName;
        si.wShowWindow = TRUE;
        si.dwFlags     = STARTF_USESHOWWINDOW;


        std::wstring wstr;
        //这里是想启动的程序的路径
        std::string str = (QCoreApplication::applicationDirPath()+"/"+PROGRAMNAME).toStdString();
        wstr = std::wstring(str.begin(),str.end());
        LPWSTR lp = (LPWSTR)wstr.c_str();


        LPVOID pEnv = NULL;
        if(FALSE == CreateEnvironmentBlock(&pEnv,hToken,FALSE))
        {
            bSuccess = FALSE;
            //logger->TraceInfo("CreateEnvironmentBlock failed");
            continue;
        }


        DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE|CREATE_UNICODE_ENVIRONMENT;
        if(!CreateProcessAsUser(hToken,NULL,lp,NULL,NULL,FALSE,dwCreationFlag,pEnv,NULL,&si,&pi))
        {
            bSuccess = FALSE;
            //logger->TraceInfo("CreateProcessAsUser erong %d",GetLastError());
            continue;
        }


        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);


        if (hToken != NULL)
            CloseHandle(hToken);
        if (pEnv != NULL)
            DestroyEnvironmentBlock(pEnv);

 注意:

1.如果是非管理员用户,服务是无法调用管理员用户的程序,只能启动普通用户的程序。

2.service只能启动普通用户权限的程序,不能启动以管理员权限运行(UAC)的程序。

 

demo及使用说明

https://github.com/fengxieye/Qt-demo/tree/master/service

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
在Qt中启动外部程序可以使用QProcess类。下面是一个简单的示例: ```cpp #include <QCoreApplication> #include <QProcess> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 创建一个QProcess对象 QProcess process; // 设置要启动程序名称和参数 QString program = "notepad.exe"; QStringList arguments; arguments << "test.txt"; // 启动外部程序 process.start(program, arguments); // 等待程序退出 process.waitForFinished(); return a.exec(); } ``` 在上面的示例中,我们使用QProcess类创建了一个名为process的对象,然后设置了要启动程序名称和参数。最后,我们调用start()方法来启动外部程序,并使用waitForFinished()方法等待程序退出。 注意:在Windows系统中,如果要启动程序不在系统路径中,需要指定程序的完整路径。例如: ```cpp QString program = "C:/Program Files (x86)/Microsoft Office/root/Office16/winword.exe"; ``` 另外,如果要启动程序需要管理员权限,需要在程序中加入以下代码: ```cpp process.setCreateProcessArgumentsModifier([](QProcess::CreateProcessArguments *args){ args->flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; args->startupInfo->dwFlags &= ~STARTF_USESTDHANDLES; args->startupInfo->cb = sizeof(STARTUPINFOEXW); args->startupInfo->lpAttributeList = nullptr; }); process.setProcessChannelMode(QProcess::MergedChannels); process.start("C:/Windows/System32/cmd.exe", QStringList() << "/c" << "netsh interface set interface \"以太网\" admin=enable"); ``` 这里的代码是启动一个命令行窗口,并以管理员权限执行了一个命令。注意:这种方法只在Windows系统中有效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值