Я пишу программу, которая использует SetWindowRgn для создания прозрачных отверстий в окне, принадлежащем другому процессу. (Это делается только тогда, когда пользователь явно запрашивает это.)
Программа должна предположить, что в целевом окне уже могут быть дыры, которые необходимо сохранить, поэтому перед вызовом SetWindowRgn она вызывает GetWindowRgn, чтобы получить текущую область, затем объединяет текущую область с новой и вызывает SetWindowRgn:
HRGN rgnOld = CreateRectRgn ( 0, 0, 0, 0 );
int regionType = GetWindowRgn ( hwnd, rgnOld );
Это нормально работает в XP, но вызов GetWindowRgn не работает в Vista. Я попытался отключить Aero и повысить привилегию моего потока до SE_DEBUG_NAME с помощью AdjustTokenPrivileges, но ничего не помогает.
GetLastError (), похоже, не возвращает допустимое значение для GetWindowRgn - он возвращает 0 на одном компьютере и 5 (доступ запрещен) на другом.
Может ли кто-нибудь сказать мне, что я делаю не так, или предложить другой подход?





Вы уверены, что ваше окно имеет это регион? Большинство окон верхнего уровня в XP работают просто потому, что тема по умолчанию использует их для закругления углов ... но это все еще плохое предположение, и оно вполне может потерпеть неудачу, когда вы перейдете в Vista.
Если вы еще не установили регион и вызов не работает, используйте разумное значение по умолчанию (прямоугольник окна) и не позволяйте ему разрушать вашу жизнь. Теперь, если SetWindowRgn() выйдет из строя ...
Спасибо, Шог. Ты сделал это. Я предполагал (не осознавая этого), что окна всегда имеют области. Переписал. Теперь, когда GetWindowRgn не работает, он устанавливает область на основе прямоугольника окна. Прекрасно работает. Это лучший ответ, который я получил на форуме за долгое время. /отдать честь
Вы упоминаете, что пытаетесь получить область окна другой процесс. Vista повысила безопасность многих межпроцессных вызовов Win32. Я не могу найти какую-либо документацию для GetWindowRgn(), но вы можете достаточно просто протестировать ее. Создайте простой проект, который устанавливает собственный регион, и попробуйте использовать свое исходное приложение, чтобы получить регион простого приложения. Если это сработает, то это будет просто раздражать, и люди не смогут использовать ваше приложение ни на чем. Если это не сработает, есть вероятность, что ваше приложение вообще не будет работать в Vista.
Я тестировал собственное приложение. Это было первое, что я сделал. Кроме того, как я уже упоминал (с досадной опечаткой), я повысил уровень привилегий для отладки. Кроме того, когда я писал ранее, я знал, что SetWindowRgn отлично работает в Vista. Я думал маловероятно, что Vista разрешает установку, но запрещает получение.
В Vista, чтобы процесс, который не запускается от имени администратора, нацелился на окно другого процесса, он должен:
Вот образец манифеста:
<?xml version = "1.0" encoding = "UTF-8" standalone = "yes"?>
<assembly xmlns = "urn:schemas-microsoft-com:asm.v1" manifestVersion = "1.0">
<assemblyIdentity version = "1.0.0.0" processorArchitecture = "X86" name = "yourAssemblyNameWithoutExtension" type = "win32"/>
<trustInfo xmlns = "urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level = "asInvoker" uiAccess = "true" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
Как так хорошо заметил Фредди, это не решает ЕГО проблему. Этот манифест требуется, если вы нацелены на процессы с повышенными или изолированными (например, IE7) от процесса без повышенных прав.
Эта функция не работает в Vista и Windows 7, то есть возвращает ERROR.
Но эта функция хорошо работает в Windows XP.
Поэтому я бы посоветовал следующее несложное решение: Если вы используете эту функцию в приложении, которое должно быть запущено под другой Windows выполните такой тест: int nResultOfRgnOperation = :: GetWindowRegion (...); если (nResultOfRgnOperation! = ОШИБКА) <Далее использовать всю область окна, определенную этой функцией> еще <Найдите ограничивающий прямоугольник для всего окна и используйте далее этот ограничивающий прямоугольник вместо области окна. При необходимости вы можете создать прямоугольную область, представляющую ограничивающий прямоугольник. >
Используйте соответствующий код в местах, отмеченных выше как <...>
Спасибо за энтузиазм.
Если в MSDN явно не указано, что вы можете вызвать GetLastError () для получения дополнительных сведений об ошибке, GetLastError () вернет случайное значение. Вы можете вызвать SetLastError (1234) до того, как GetWindowRgn (), и GetLastError () после этого всегда будет возвращать 1234.