user1431006
user1431006

Reputation: 11

EnumDesktopWindows Error: (183) Cannot create a file when that file already exists

Anyone know why returns 183 in call EnumDesktopWindows

This process is an service running in System LocalService

I'm trying to put the window in the top, because the process starts minimized.

Thank for Help

My Code:

BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam ) 
{
    DWORD dwPID;
    GetWindowThreadProcessId( hwnd, &dwPID );

    if( dwPID == lParam ) {
        SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,  SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE );
        SwitchToThisWindow(hwnd, true);
        SetFocus( hwnd );
        return FALSE;
    }

    return TRUE;
}

BOOL CALLBACK EnumDesktopProc(LPTSTR lpszDesktop, LPARAM lParam) {
    HDESK hDesk = OpenDesktop(lpszDesktop, NULL, FALSE, GENERIC_ALL);

    if(hDesk != NULL) {

        if(!EnumDesktopWindows(hDesk,&EnumWindowsProc, lParam)) {
            //This call returns (183) Cannot create a file when that file already exists
        }

        CloseDesktop(hDesk);
    }

    return TRUE;
}


BOOL CALLBACK EnumWindowStationProc(LPTSTR lpszWindowStation, LPARAM lParam)
{

    HWINSTA hWinStat = OpenWindowStation(lpszWindowStation,FALSE,WINSTA_ENUMDESKTOPS|WINSTA_ENUMERATE); 

    if(hWinStat) {
        SetProcessWindowStation(hWinStat);
        EnumDesktops(hWinStat,&EnumDesktopProc,lParam);
        CloseWindowStation(hWinStat);
    }

    return TRUE;
}


bool Utils::execIntoDifferentSession(const std::wstring &aPath, const std::wstring &aParams, const std::wstring &aMode) 
{
    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 false;

    procEntry.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(hSnap, &procEntry))
        return false;

    do {
        if (_wcsicmp(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 = L"winsta0\\default";
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_SHOWNORMAL|SW_RESTORE;

    ZeroMemory(&pi, sizeof(pi));
    TOKEN_PRIVILEGES tp;
    LUID luid;
    hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);

    if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY
                                    |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID
                                    |TOKEN_READ|TOKEN_WRITE,&hPToken))
    {
        return false;
    }

    if (!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid))
        return false;

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);

    //Adjust Token privilege
    SetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD));

    if (!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL))
        return false;

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
        return false;

    LPVOID pEnv = NULL;

    if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE))
        dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
    else
        pEnv = NULL;

    // Launch the process in the client's logon session.

    std::wstring params = aParams;
    std::wstring path = aPath;

    if(aMode == L"select") {
        TCHAR infoBuffer[MAX_PATH];
        GetSystemWindowsDirectory(infoBuffer, MAX_PATH);
        std::wstring windowsDir(infoBuffer);

        path = windowsDir+L"\\explorer.exe";
        params = L" /n, /select,"+replaceString(aPath, L"\\\\", L"\\");
    }

    bResult = CreateProcessAsUser(
        hUserTokenDup,     // client's access token
        path.c_str(),      // file to execute
        params.length() > 0 ? stringToLPWSTR(wideToUtf8(params)) : NULL,              // 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
    );

    EnumWindowStations(&EnumWindowStationProc, (LPARAM)(pi.dwProcessId));

    // End impersonation of client.

    //GetLastError Shud be 0

    int rv = GetLastError();

    //Perform All the Close Handles task

    CloseHandle(hProcess);
    CloseHandle(hUserToken);
    CloseHandle(hUserTokenDup);
    CloseHandle(hPToken);

    return !rv;
}

Upvotes: 1

Views: 1929

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595295

Error 183 is ERROR_ALREADY_EXISTS. EnumDesktopWindows() does not set that error, so it must be a carry-over from an earlier API call. If you read the documentation says this:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682615.aspx

You must ensure that the callback function sets SetLastError if it fails.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682614.aspx

If the callback function fails, the return value is zero. The callback function can call SetLastError to set an error code for the caller to retrieve by calling GetLastError.

So try something more like this:

struct WndInfo
{
    DWORD dwProcessID;
    HWND hWnd;
};

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) 
{
    WndInfo *pInfo = (WndInfo*) lParam;

    DWORD dwPID;
    GetWindowThreadProcessId(hwnd, &dwPID);

    if (dwPID == pInfo->dwProcessID)
    {
        pInfo->hWnd = hwnd;
        SetLastError(0);
        return FALSE;
    }

    return TRUE;
}

BOOL CALLBACK EnumDesktopProc(LPTSTR lpszDesktop, LPARAM lParam)
{
    HDESK hDesk = OpenDesktop(lpszDesktop, NULL, FALSE, GENERIC_ALL);
    if (hDesk != NULL)
    {
        if (!EnumDesktopWindows(hDesk, &EnumWindowsProc, lParam))
        {
            if (GetLastError() != 0)
            {
                // handle error as needed...
            }
        }

        CloseDesktop(hDesk);

        WndInfo *pInfo = (WndInfo*) lParam;
        if (pInfo->hWnd != NULL)
        {
            SetLastError(0);
            return FALSE;
        }
    }

    return TRUE;
}

BOOL CALLBACK EnumWindowStationProc(LPTSTR lpszWindowStation, LPARAM lParam)
{
    HWINSTA hWinStat = OpenWindowStation(lpszWindowStation, FALSE, WINSTA_ENUMDESKTOPS|WINSTA_ENUMERATE); 
    if (hWinStat != NULL)
    {
        SetProcessWindowStation(hWinStat);

        if (!EnumDesktops(hWinStat, &EnumDesktopProc, lParam))
        {
            if (GetLastError() != 0)
            {
                // handle error as needed...
            }
        }

        CloseWindowStation(hWinStat);

        WndInfo *pInfo = (WndInfo*) lParam;
        if (pInfo->hWnd != NULL)
        {
            SetLastError(0);
            return FALSE;
        }
    }

    return TRUE;
}

HWND findWindowForProcess(DWORD PID)
{
    WndInfo info;
    info.dwProcessID = PID;
    info.hWnd = NULL;

    if (!EnumWindowStations(&EnumWindowStationProc, (LPARAM)&info))
    {
        if (GetLastError() != 0)
        {
            // handle error as needed...
        }
    }

    return info.hWnd;
}
bool Utils::execIntoDifferentSession(const std::wstring &aPath, const std::wstring &aParams, const std::wstring &aMode) 
{
    ...
    bResult = CreateProcessAsUser(...);
    if (bResult)
    {
        HWND hWnd = findWindowForProcess(pi.dwProcessId);
        if (hWnd != NULL)
        {
            SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
            SwitchToThisWindow(hWnd, TRUE);
            SetFocus(hWnd);
        }
    }
    ...   
}

With that said, since all you are really trying to do is execute a new process in a specific user session, you don't need to bother with all that enumeration logic. You don't need to find the WinLogon process at all, you already have the user's token from WTSQueryUserToken() so just duplicate+adjust that token as needed. And you are not doing anything useful in your window enumeration that the new process would not already do by default when it is started, so just get rid of that logic, too.

And then finally fix your error handling (or lack of) so you can close any handles that are open and not leak them.

Upvotes: 1

Related Questions