모두의 프린터는 어떠한 경우에도 회원가입, 카드결제를 요구하지 않습니다.

CreateProcessAsUser – 서비스에서 GUI포함한 프로그램 실행

일반적으로 윈서 서비스 프로그램은 일반 어플리케이션과 다른 영역에서 실행되기 때문에.. 서비스가 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;
}

%d