Снимок экрана Windows: и GDI, и DirectX не работают, возвращает ACCESS_DENIED

Я снимаю экраны в Windows, используя DirectX и GDI соответственно на основе операционной системы (DirectX (дублирование рабочего стола) - для Win8 и выше и GDI для Win7 и ниже или в качестве запасного варианта в случае любой ошибки с подходом DirectX).

Редко на некоторых машинах я получаю и GDI, и DirectX возвращают ошибку ACCESS_DENIED на экране winlogon.

Переключатели рабочего стола обнаруживаются и устанавливаются правильно, а приложение работает с повышенными правами пользователя. При настройке рабочего стола ошибки не возникает. И тот же поток, который захватывает экран, вызывает функцию, которая устанавливает текущий рабочий стол в текущий поток. Приложение не запускается ни на одном сеансе RDP, как проблема, упомянутая здесь и здесь.

Я сделал много анализа и исследований. Я просмотрел исходные коды приложений для захвата экрана с открытым исходным кодом, но не нашел ничего полезного. Это заняло у меня неделю без какого-либо прогресса в этой проблеме.

Вот код для настройки текущего рабочего стола

if (GetCurrentDesktop(aCurrentDesktop) && _tcscmp(aCurrentDesktop, aPrevDesktop) != 0)
{
    ScreenCaptureUtils::SetProcessWindowStation();

        HDESK hcurrentInputDesktop = OpenInputDesktop(0, FALSE, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);

        if(hcurrentInputDesktop != NULL)
        {
            if(!SetThreadDesktop(hcurrentInputDesktop))
            {
                errorCode = GetLastError();
                LOG << _T("setCurrentInputDesktop: SetThreadDesktop failed. Error code: ") << errorCode;
            }
            else
            {
                errorCode = ERROR_SUCCESS;

                _tcscpy_s (aPrevDesktop, MAX_PATH, aCurrentDesktop);

                LOG << _T("setCurrentInputDesktop: SetThreadDesktop succeeded.");
            }

            hPrevDesk = hcurrentInputDesktop;

            CloseDesktop(hcurrentInputDesktop);
        }
        else
        {
            errorCode = GetLastError();
            LOG << _T("setCurrentInputDesktop: OpenInputDesktop failed. Error code: ") << errorCode;
        }
}
else
{
    LOG << _T("setCurrentInputDesktop: OpenInputDesktop failed. Error code: ") << errorCode;
}

bool GetCurrentDesktop ( TCHAR * desktopName )  
{
    {
        HDESK  hDesktop = ::OpenInputDesktop(0, FALSE, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);

        if (!hDesktop)
        {
            return  false;
        }

        DWORD dw = 0;
        TCHAR  szName[MAX_PATH];
        ::memset(szName, 0, sizeof(szName));

        if (!::GetUserObjectInformation(hDesktop, UOI_NAME, &szName, sizeof(szName), &dw))
        {
            ::CloseDesktop(hDesktop);

            return false;
        }

        _tcscpy(desktopName, szName);

        ::CloseDesktop(hDesktop);
    }

}

Код для захвата экрана похож на следующий

int screenCapture()
{
    int result = -1;

    int width = 1000;
    int height = 700;

    HDC hdcTemp, hdc;
    BYTE* bitPointer;

    hdc = GetDC(HWND_DESKTOP);
    if (hdc != NULL)
    {
        hdcTemp = CreateCompatibleDC(hdc);
        if (hdcTemp != NULL)
        {
            BITMAPINFO bitmap;
            bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
            bitmap.bmiHeader.biWidth = width;
            bitmap.bmiHeader.biHeight = -height;
            bitmap.bmiHeader.biPlanes = 1;
            bitmap.bmiHeader.biBitCount = 24;
            bitmap.bmiHeader.biCompression = BI_RGB;
            bitmap.bmiHeader.biSizeImage = 0;
            bitmap.bmiHeader.biClrUsed = 0;
            bitmap.bmiHeader.biClrImportant = 0;

            HBITMAP hBitmap = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)&bitPointer, NULL, NULL);
            if (hBitmap != NULL)
            {
                HBITMAP hPrevBitmap = SelectObject(hdcTemp, hBitmap);

                BitBlt(hdcTemp, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
                result = (int) bitPointer[0];

                SelectObject(hdcTemp, hPrevBitmap);
                DeleteObject(hBitmap);
            }

            DeleteDC(hdcTemp);
       }

       ReleaseDC(HWND_DESKTOP, hdc);
    }

    return result;
}

Я звоню GetDC с именем текущего монитора. Это связано с вызовом GetDC с NULL в качестве параметра? Но это не выглядит проблемой согласно этому.

Любая помощь будет оценена. Заранее спасибо.

0 ответов

Другие вопросы по тегам