| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Delphi: WinAPI и системное программирование > ScreenShot окна UAC в win7 |
| Автор: yogin 9.4.2012, 22:01 | ||
| Есть приложение, делает скрины каждые 10 секунд и сохраняет их на диске(регистратор визуальных действий). Недавно заметил, что окно "Контроль учётных записей пользователей" совсем не фоткается - его нет на скринах. А оно так часто появляется... почти при запуске каждой проги. Как его запечатлить? Скрин делается обычным способом:
Может нужно скринить как-то по другому? Или ещё есть мысль - может быть нужно проматывать все существующие окна, смотреть на их какие-нибудь идентификаторы и определять UAC это окно или нет и если да, то скринить само окно через его дескриптор? И следующий вопрос, а даст ли система свободу на все эти действия или тоже увильнёт как и от скрина?... |
| Автор: kami 9.4.2012, 22:27 |
| UAC "выскакивает" на отдельном десктопе. Порядок действия его, afair, следующий: - скрин десктопа - переключение на специфический десктоп - отображение скрина - создание окна "запустить/не запустить" Соответственно, если скриншотящее приложение запущено под пользовательской терминальной сессией (и т.д.), то нужно пробовать SetThreadDektop, чтобы суметь сделать скрин этого специфического десктопа. Afair, читал это в статьях Руссиновича. |
| Автор: kami 9.4.2012, 22:44 | ||
|
| Автор: yogin 10.4.2012, 18:21 |
| Так... правильно ли я понял, что мне надо запомнить Handle текущего десктопа методом GetThreadDesktop(GetCurrentThreadId), затем как-то узнать Handle десктопа, созданного UAC'ом, потом переключиться на него командой SwitchDesktop(), сделать скрин обычным методом через GetDC(0), а потом переключиться обратно тем же методом SwitchDesktop(OldDT) ? Тогда вопрос, а как узнать хэндл окна UAC'а? Или второй вариант: мне надо не GetDC(0) делать, а постоянно вызывать сначало GetThreadDesktop(GetCurrentThreadId), и уже относительно результата получать дескриптор? Тогда вопрос, как получать дескриптор в этом случае? так: GetDC(GetThreadDesktop(GetCurrentThreadId)) ? |
| Автор: kami 11.4.2012, 13:13 |
| не совсем так. Есть ряд проблем с этой задачей. 1. Я не нашел функцию, позволяющую отследить смену десктопа, наподобие http://msdn.microsoft.com/en-us/library/windows/desktop/aa383841(v=vs.85).aspx, без этого имхо придется постоянно отслеживать через OpenInputDesktop 2. C учетом того, что UAC показывается на Winlogon -десктопе. http://msdn.microsoft.com/en-us/library/windows/desktop/ms682573(v=vs.85).aspx. Это печально. Вообще - читать http://msdn.microsoft.com/en-us/library/windows/desktop/ms686744(v=vs.85).aspx. Могу посоветовать обратиться к Eraser-у на форуме delphimaster.ru, он при создании своего RemoteOfficeManager как-то обошел это. Если отбросить все сложности, то (имхо) должно выглядеть так: 1. Запоминаем текущий десктоп потока. 2. OpenInputDesktop 3. SetThreadDesktop 4. Снимок экрана 5. SetThreadDesktop(старый десктоп) 6. Освободить все полученные хендлы. Кстати, не стоит забывать, что Winlogon - не единственный десктоп, отличный от winsta0\default. Есть куча программ (например, Марка Руссиновича), которые создают дополнительные десктопы и позволяют оперативно переключаться между ними. Иногда - очень полезная штука Вечером еще пошукаю MSDN, но думаю нечего нового не скажу. |
| Автор: yogin 11.4.2012, 18:02 | ||
В ROM'е используется драйвер стандартного MS'овского удалённого рабочего стола. Так что это не то... |
| Автор: yogin 18.5.2012, 20:30 |
| Правильно ли я понял, что перед каждым снимком мне надо создавать новый десктоп(OpenInputDesktop), потом фоткать обычным методом(GetDC(0)), а потом возвращаться к предыдущему десктопу. При этом фоткаться будет всё, т.к. мой новый десктоп будет как бы поверх всех существующих?... |
| Автор: yogin 19.5.2012, 14:06 | ||||
Кароч делаю так:
SetThreadDesktop всегда False, т.к.: <<MSDN - function SetThreadDesktop - Remarks>>
Поэтому сдаётся мне процесс скрининга надо реализовывать сервисным приложением... И видимо надо интерактивный сервис, чтобы скрин как-то передават "нормальному" приложению с формой, которое уже будет выполнять сохранение куда надо или отображение на форме... |
| Автор: kami 19.5.2012, 17:42 | ||||
к потоку в сервисе ведь точно такие же требования - отсутствие окон и хуков при переключении. Причем окно ведь не обязательно визуальное, хватит и таймера, в котором используется AllocateHwnd. В ОС, в которых появился UAC, интерактивные сервисы запрещены. В Vista была специализированная служба, которая отлавливала попытку отображения чего-то визуального интерактивным сервисом и предлагала показать "это" на специализированном десктопе, не имеющем никакого отношения к Winlogon-у. А вообще, интерактивные службы в Vista и 7 не являются такими, какими они задумывались изначально - они не имеют доступа даже к обычному десктопу обычного пользователя, так как находятся в отличной от пользовательской терминальной сессии. То есть - не являются интерактивными.
Обычно делают наоборот |
| Автор: CodeMonkey 20.5.2012, 23:46 |
| http://stackoverflow.com/questions/4046940/how-to-screen-shot-a-uac-prompt |
| Автор: yogin 22.5.2012, 12:07 |
Хорошо, тогда обычный сервис, но порядок действий-то будет в нём таким же? Тогда просто самим сервисом сохранять файлы? CodeMonkey, я сделал так как там написано(вручную отключил), но обычные методы скрининга всё равно не запечатлили окно UAC, лишь тень от него. |
| Автор: yogin 1.6.2012, 09:56 |
| Опытным путём метода тыка выяснено: 1) что фотки UAC'а получаются в нормальном приложении, если это приложение запустить от имени системы... 2) а служба не может ничего сфоткать потому что ей в нормальном режиме десктопы не доступны(в 7-ке)... Вытекающие вопросы: 1) как можно службой запустить приложение, чтобы у него были её права(или права системы), но при этом оно имело доступ к едсктопам? 2) можно ли как-то в винде назначить, чтобы прога автоматом запускалась с правами системы? |
| Автор: kami 1.6.2012, 13:13 | ||||
Ага, у пользователя своя терминальная сессия, а у сервисов - своя. И у каждой своя WinSta и свой десктоп...
Единственное, что нашел - это http://msdn.microsoft.com/en-us/library/Aa379608. Но, хоть в community пишут, что она работает (только acl-ы нужно потом удалить, даже код есть как) у меня не получилось портировать это хозяйство на Delphi. Вернее, получилось (отрабатывает без ошибок), но процесс запускается не интерактивный, а непойми в какой WinSta... До того, как увидел этот код, получалось запустить из сервиса десктопное приложение, но так как токену сессии, от которой запускался процесс, не давали права админа (было Deny), то ни о каких дополнительных плюшках речи не шло. К сожалению, Deny ни на что другое поменять нельзя... На последний вопрос ничего не скажу - не знаю... Добавлено @ 13:20 Кстати, не пробовал еще получать токен не через LogonUser, а через GetActiveConsoleSessionID и далее... |
| Автор: drkot 1.6.2012, 14:25 | ||
Сразу оговорюсь... то что напишу не есть "правильно" с точки зрения системного подхода ОС, но значительно проще и гуманнее относительно программиста. Принцип прост: любое приложение может посылать (создавать) записи в системном журнале событий. В системном планировщике есть возможность привязки задачи к журналу событий. Для реализации такого механизма не нужно ковырять права и переключаться между сессиями... что значительно упростит задачу для начинающего. Права на запуск задаются в том же планировщике |