EnumDesktopWindows错误:(183)当该文件已存在时无法创建文件

时间:2014-06-25 20:39:48

标签: c++ windows winapi c++11 service

任何人都知道为什么在调用EnumDesktopWindows

时返回183

此过程是在System LocalService

中运行的服务

我试图将窗口置于顶部,因为过程开始最小化。

感谢帮助

我的代码:

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;
}

1 个答案:

答案 0 :(得分:1)

错误183是ERROR_ALREADY_EXISTSEnumDesktopWindows()未设置该错误,因此它必须是早期API调用的结转。如果您阅读文档说明:

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

  

如果失败,您必须确保回调函数设置SetLastError。

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

  

如果回调函数失败,则返回值为零。回调函数可以调用SetLastError来设置错误代码,以便调用者通过调用GetLastError来检索。

所以尝试更像这样的东西:

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);
        }
    }
    ...   
}

话虽如此,因为你真正想要做的就是在特定的用户会话中执行一个新的过程,你不需要为所有的枚举逻辑而烦恼。您根本不需要找到WinLogon进程,您已经拥有来自WTSQueryUserToken()的用户令牌,因此只需复制+根据需要调整该令牌。并且你没有在窗口枚举中做任何有用的事情,新进程在启动时默认不会这样做,所以也要摆脱那个逻辑。

然后最后修复你的错误处理(或缺少),这样你就可以关闭任何打开的句柄而不会泄漏它们。