(183)当文件已经存在时,无法创建文件

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

本文关键字:文件 创建 存在      更新时间:2023-10-16

有谁知道为什么在call EnumDesktopWindows中返回183

这个进程是在System LocalService

中运行的一个服务

我试着把窗口放在最上面,因为这个过程开始是最小化的。

Thank for Help

我代码:

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

错误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

如果回调函数失败,返回值为0。回调函数可以调用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()获得了用户的令牌,因此只需根据需要复制+调整该令牌。并且,您没有在窗口枚举中做任何新进程启动时默认不会做的有用的事情,因此,也请删除该逻辑。

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