일반적으로 윈서 서비스 프로그램은 일반 어플리케이션과 다른 영역에서 실행되기 때문에.. 서비스가 SheelExecute나 CreateProcess 함수등으로 실행한 프로그램들은 GUI를 포함하고 있다하더라도 화면에 표시되지 않습니다.
이러한 이유로 서비스 프로세스에서 .. GUI를 포함한 프로그램을 실행하려 하는 경우에는 ..
CreateProcessAsUser 함수를 통해서 실행을 해줘야 합니다.
이떄 사용가능한 함수인데요..
이 함수 인자가 2개인데요 szExeName, lpCommandLine 2개인데 ..
흔히들 이런 구조면 .. 실행파일명을 szExeName 에 나머지 인자를 lpCommandLine 에 넣어 쓰기 마련인데 그리 쓰시면 안됩니다.
만약 그냥 인자없이 실행하실거면 .. szExeName 에다 실행파일명만 달랑 넣으시고 lpCommandLine은 NULL을
만약 실행인자를 포함해서 실행 하실거면 szExeName 은 NULL, 실행파일과 인자까지 포함한 전체 실행명령을 lpCommandLine 에 전달하시면 됩니다.
C++
/**
* RunPrucessAsUser
**/
BOOL RunProcessAsUser(TCHAR* szExeName, LPWSTR lpCommandLine) {
PROCESS_INFORMATION pi;
STARTUPINFO si;
BOOL bResult = FALSE;
DWORD dwSessionId, winlogonPid;
HANDLE hUserToken, hUserTokenDup, hPToken, hProcess;
DWORD dwCreationFlags;
// Log the client on to the local computer.
dwSessionId = WTSGetActiveConsoleSessionId();
//////////////////////////////////////////
// Find the winlogon process
////////////////////////////////////////
PROCESSENTRY32 procEntry;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE)
{
return 1;
}
procEntry.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnap, &procEntry))
{
return 1;
}
do
{
if (wcscmp(procEntry.szExeFile, L"winlogon.exe") == 0)
{
// We found a winlogon process...make sure it's running in the console session
DWORD winlogonSessId = 0;
if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) && winlogonSessId == dwSessionId)
{
winlogonPid = procEntry.th32ProcessID;
break;
}
}
} while (Process32Next(hSnap, &procEntry));
////////////////////////////////////////////////////////////////////////
WTSQueryUserToken(dwSessionId, &hUserToken);
dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = (LPWSTR)L"winsta0\\default";
ZeroMemory(&pi, sizeof(pi));
TOKEN_PRIVILEGES tp;
LUID luid;
hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, winlogonPid);
OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
| TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID
| TOKEN_READ | TOKEN_WRITE, &hPToken);
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hUserTokenDup);
int dup = GetLastError();
//Adjust Token privilege
SetTokenInformation(hUserTokenDup, TokenSessionId, (void*)dwSessionId, sizeof(DWORD));
AdjustTokenPrivileges(hUserTokenDup, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, NULL);
LPVOID pEnv = NULL;
if (CreateEnvironmentBlock(&pEnv, hUserTokenDup, TRUE))
{
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
}
else
pEnv = NULL;
// Launch the process in the client's logon session.
bResult = CreateProcessAsUser(
hUserTokenDup, // client's access token
szExeName, // file to execute
lpCommandLine, // command line
NULL, // pointer to process SECURITY_ATTRIBUTES
NULL, // pointer to thread SECURITY_ATTRIBUTES
FALSE, // handles are not inheritable
dwCreationFlags, // creation flags
pEnv, // pointer to new environment block
NULL, // name of current directory
&si, // pointer to STARTUPINFO structure
&pi // receives information about new process
);
// End impersonation of client.
//GetLastError Shud be 0
int iResultOfCreateProcessAsUser = GetLastError();
//Perform All the Close Handles task
if (pi.hProcess != NULL) {
DWORD dwWait = ::WaitForInputIdle(pi.hProcess, INFINITE);
::CloseHandle(pi.hProcess);
}
if (hProcess != NULL) {
CloseHandle(hProcess);
}
if (hUserToken != NULL) {
CloseHandle(hUserToken);
}
if (hUserTokenDup != NULL) {
CloseHandle(hUserTokenDup);
}
if (hPToken != NULL) {
CloseHandle(hPToken);
}
return bResult;
}