如何使MFC编写的程序作为服务运行,并正常显示界面

本文介绍在Win7及以后的Windows版本中,如何让MFC编写的程序作为服务运行,并解决因Session隔离导致的界面无法显示的问题。通过获取进程访问令牌、创建新访问令牌和切换Session,使得服务能够正常启动并显示用户界面。
摘要由CSDN通过智能技术生成

Win7以及之后的windows版本下启动一个服务,在服务中创建一个带UI的进程

服务启动代码:

#pragma once

#pragma execution_character_set("utf-8")
#include "stdafx.h"
#include <winsvc.h>
#include "ManagerService.h"
#include "log.hpp"
#include <tlhelp32.h >
#include <Userenv.h>


#pragma comment(lib, "Userenv.lib") 


#define FRONT_START 0                 // 服务启动
#define FRONT_STOP    1                // 服务停止
#define FRONT_PAUSE 2                // 服务暂停


static SERVICE_STATUS               g_ServiceStatus; //服务的状态
static SERVICE_STATUS_HANDLE    g_ServiceStatusHandle; //
static PROCESS_INFORMATION        g_ProcessInfo; //要启动的进程信息
static HANDLE  hEvents[4] = { 0 };
TCHAR g_strServiceName[MAX_PATH] = {0}; //服务的名称


VOID WINAPI ServiceMain(DWORD   dwNumServicesArgs,  LPWSTR  *lpServiceArgVectors)
{
    Log("ServiceMain begin\n");
    // Register the control request handler
    hEvents[0] = CreateEvent(NULL, FALSE, FALSE, _T("FRONTSTART"));
    hEvents[1] = CreateEvent(NULL, FALSE, FALSE, _T("FRONTSTOP"));
    hEvents[2] = CreateEvent(NULL, FALSE, FALSE, _T("FRONTPAUSE"));
    hEvents[3] = (HANDLE)0;

   //注册控制 Control Handler
    g_ServiceStatusHandle = RegisterServiceCtrlHandler(g_strServiceName, ServiceCtrlHandler);
    if (g_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
    {
        Log("Handler not installed\n");
        return;
    }

    CoInitialize(0);
    STARTUPINFO si;
    


    // 设置服务状态为服务已经启动
    g_ServiceStatus.dwCurrentState  = SERVICE_RUNNING;
    SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);


    DWORD dwRet = WAIT_FAILED;
    int iFlag = FRONT_START;
    while (1)
    {
        if ((iFlag == FRONT_START || iFlag == FRONT_PAUSE) && (dwRet == WAIT_OBJECT_0 + 1))            // 要求停止服务的事件发生
        {
            TerminateProcess(g_ProcessInfo.hProcess, 0);
            CloseHandle(g_ProcessInfo.hProcess);
            g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);
            iFlag = FRONT_STOP;
    Log("Front exit \n");
            return;
        }
        if ((iFlag == FRONT_STOP || iFlag == FRONT_PAUSE) && (dwRet == WAIT_OBJECT_0))                // 要求启动服务的事件发生
        {
            iFlag = FRONT_START;
            g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
            SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);
            Log("FRONT_START \n");
        }


        if ((iFlag == FRONT_START) && (dwRet == WAIT_OBJECT_0 + 2))            // 要求暂停服务的事件发生
        {
            TerminateProcess(g_ProcessInfo.hProcess, 0);
            CloseHandle(g_ProcessInfo.hProcess);
            g_ServiceStatus.dwCurrentState = SERVICE_PAUSED;
            SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);
            iFlag = FRONT_PAUSE;


            Log("ServiceMain FRONT_PAUSE\n");
        }


        if (iFlag == FRONT_START)                                        // 只在允许启动的情况下才去启动
        {
            if (dwRet == WAIT_OBJECT_0 + 3 || dwRet == WAIT_FAILED)        // 进程意外退出或者还未启动
            {
                if (dwRet == WAIT_OBJECT_0 + 3)
                {
                    Log(string("Front exit!!!").c_str());
                }


                // 记录进程退出日志
                memset(&si, 0, sizeof(STARTUPINFO));
                si.cb = sizeof(STARTUPINFO);
                si.lpReserved = NULL;
si.lpDesktop = _T("WinSta0\\Default");
                si.lpTitle = NULL;
                si.dwFlags = STARTF_USESHOWWINDOW;
//                si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
                si.wShowWindow = SW_SHOW;
                si.cbReserved2 = NULL;
                si.lpReserved2 = NULL;
                TCHAR szPath[MAX_PATH];

//获取服务当前的路径
                if (!GetModuleFileName(NULL, szPath, MAX_PATH))//if (!GetModuleFileName(_T(""), szPath, MAX_PATH))
                {
                    int err = GetLastError();
                    char data[100] = { 0 };
                    sprintf(data, "GetModuleFileName failed(%d)\n", err);
                    Log(data);
                }
                else
                {
HANDLE hToken = NULL;
HANDLE hTokenDup = NULL;
bool bSuccess = TRUE;
do

{

//为了防止进程在后台启动,session隔离(在Vista 和 win7及之后的windows版本中有了session隔离)问题导致不能显示界面。被称为winsta0的Session才被允许与用户交互。因此,下文将切换Session,以便正常显示界面

//首先,获取进程访问令牌的句柄

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值