Scrrenshot с экрана и RDP
От: Аноним  
Дата: 13.04.09 22:42
Оценка:
Здравствуйте, коллеги.
Есть такая проблема: приложение должно получать скриншоты экрана пользователя, причём даже в том случае, если пользователь подключён при помощи RDP. Для этого в активной терминальной сессии (той сессии, в которой работает подключившийся пользователь) запускается процесс, который делает скриншоты следующим образом: при помощи GetDC(NULL) получает HDC экрана, и потом с него делает BitBlt на битмап в памяти. Такое решение неплохо работает пока пользователь подключен и работает за удалённым компьютером. Но как только он сворачивает окно удалёного рабочего стола, всё перестаёт работать. BitBlt возвращает 0, GetLastError()=6 (ERROR_INVALID_HANDLE). Причём когда пользователь разворачивает окно удалённого рабочего стола, всё опять работает нормально. Пробовал делать OpenInputDesktop/SetThreadDesktop перед вызовом BitBlt — обе функции проходят нормально, но BitBlt всё равно не работает. На машине стоит Windows XP.
Если кто-нибудь знает, в чём тут дело, помогите, пожалуйста
Заранее всем спасибо
bitblt rdp screenshot
Re: Scrrenshot с экрана и RDP
От: IZer Украина  
Дата: 18.04.09 09:59
Оценка: 25 (4)
Разобрался в чём проблема, если у кому-то ещё интересно, рассказываю:
При сворачивании экрана RDP Windows по-видимому, для экономии траффика отключает всё рисование на активном десктопе путём переключения на другой десктоп. Причём переключение происходит внутри win32k.sys, и при этом выставляется специальный флаг, в результате чего переключение десктопа из UserMode (SwitchDesktop) не оказывает никаких эффектов. Сам процесс включения/выключения отрисовки осуществляется с помощью ни откуда не экспортируемых функций NtUserRemoteRedrawScreen() и NtUserRemoteStopScreenUpdates(). Вызвать эти функции можно только напрямую через SSDT, причём при вызове код в режиме ядра проверяет, чтоб текущий процесс был процессом CSRSS.exe, иначе функция не работает. Для решения проблемы пришлось написать свою длл, которая внедряется в процес csrss (путём CreateRemoteThread) и периодически вызывает NtUserRemoteRedrawScreen(). Вот как выглядит вызов этой функции на Windows XP SP2

DWORD NtUserRemoteRedrawScreenXPSP2()
{
    DWORD dwResult;
    __asm
    {
        mov     eax, 1254h
        mov     edx, 7FFE0300h
        call    dword ptr [edx]
        mov dwResult, eax
    }
    return dwResult;
}

На Windows 2003 Server SP1 и SP2 индекс этой функции поменялся с 1254h на 1250h.
Вся эта информация была получена в ходе ковыряния внутри win32k.sys и winsrv.dll дизассемблером с установленными отладочными символами Windows (отсюда известны названия функций)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.