2017-08-07 56 views
0

體系結構是一個服務可以與系統特權,代碼段1無法關閉從服務中的用戶會話的過程

用戶會話的處理組內啓動一個進程當服務需要停止本身,我想發送一個信號給子進程,使它有機會優雅地關閉代碼片段2.

問題是它似乎沒有發送信號,沒有任何明顯的錯誤代碼。我測試了從命令提示符運行的子進程,ctrl + break工作得很好。

代碼片段

PROCESS_INFORMATION processInfo; 
ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION)); 

STARTUPINFO si; 
ZeroMemory(&si, sizeof(STARTUPINFO)); 
si.cb = sizeof(STARTUPINFO); 
si.lpDesktop = "winsta0\\Default"; 
si.dwFlags |= STARTF_USESTDHANDLES; 

LPVOID environment; 
BOOL createRet = CreateEnvironmentBlock(&environment, userToken, FALSE); 
if (!createRet) { 
    throw std::runtime_error("Failed to create environment block"); 
} 

DWORD creationFlags = 
    NORMAL_PRIORITY_CLASS | 
    CREATE_NO_WINDOW | 
    CREATE_UNICODE_ENVIRONMENT | 
    CREATE_NEW_PROCESS_GROUP; // this create a process in a group 

// launch a process in the user session 
// the toke is a system privilege toke within the user session 
createRet = CreateProcessAsUser(
    userToken, NULL, LPSTR(command.c_str()), 
    sa, NULL, TRUE, creationFlags, 
    environment, NULL, &si, &processInfo); 

if (!createRet) { 
    throw std::runtime_error("Failed to create the service in user session"); 
} 

m_serviceGroupId = processInfo.dwProcessId; 

DestroyEnvironmentBlock(environment); 
CloseHandle(userToken); 

代碼片段2

if (m_serviceGroupId == 0) { 
    return; 
} 

HANDLE process; 
const UINT kExitCode = 0; 
const UINT kShutdownTimeout = 3000; 
if (findProcessInSession(kServiceProcess, &process, getActiveSession())) { 
    BOOL r = GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, m_serviceGroupId); 
    // this won't success if I don't specifically call AllocConsole() in the constructor 
    if (!r) { 
     writeEventErrorLog(GetLastErrorAsString().c_str()); 
    } 

    DWORD exitCode = WaitForSingleObject(process, kShutdownTimeout); 
    if (exitCode != WAIT_OBJECT_0) { 
     // always fall into forceful shutdown 
     writeEventErrorLog("Forcefully shutdown synergy service"); 
     // GetLastErrorAsString returns empty string 
     writeEventErrorLog(GetLastErrorAsString().c_str()); 
     if (!TerminateProcess(process, kExitCode)) { 
      writeEventErrorLog("Failed to shutdown synergy service"); 
     } 
    } 
} 

m_serviceGroupId = 0; 
+0

'GenerateConsoleCtrlEvent'遠程調用'csrss'。但您的服務附加到另一個「csrss」進程 - 每個會話都有自己的「csrss」。所以'GenerateConsoleCtrlEvent'不能用於另一個會話中的發送控制事件 – RbMm

+0

@RbMm謝謝。我有辦法管理子進程嗎? RPC調用? – Jerry

+1

您需要做的只是從服務向孩子發送一次性消息,因此命名事件對象可能是最合適的選擇。在更復雜的情況下,您可以使用命名管道。還有其他的選擇。 –

回答

1

你的方法是行不通的,因爲服務進程和子進程不在同一個會話,因此考慮使用Windows事件。看看CreateEventSetEvent

當你的服務過程開始時,調用CreateEvent(),例如:

HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\myevent"); 

當你的子進程啓動,調用CreateEvent(),並啓動一個線程來捕獲信號:

//The lpName should be identical with that in service process 
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\myevent"); 

std::thread mythread([hEvent] { 
    WaitForSingleObject(hEvent, INFINITE); 
    //then exit your child process gracefully 
}); 

每當你打算停止子進程,只需調用SetEvent的()在您的服務流程:

SetEvent(hEvent); 

將bManualReset設置爲TRUE,然後您的服務可以同時向不同的子進程發送信號。