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,以便正常显示界面
//首先,获取进程访问令牌的句柄