Почему GetWindowRgn не работает в Vista? - PullRequest
2 голосов
/ 28 сентября 2008

Я пишу программу, которая использует 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 (доступ запрещен) на другой.

Может кто-нибудь сказать мне, что я делаю неправильно или предложить другой подход?

Ответы [ 4 ]

12 голосов
/ 28 сентября 2008

Вы уверены, что ваше окно имеет регион? Большинство окон верхнего уровня в XP делают это просто потому, что тема по умолчанию использует их для закругления углов ... но это все еще неверное предположение, и оно может не сработать, когда вы доберетесь до Vista.

Если вы еще не установили регион, и вызов не состоялся, используйте разумное значение по умолчанию (прямоугольник окна) и не позволяйте ему разрушить вашу жизнь. Теперь, если SetWindowRgn() не удается ...

2 голосов
/ 28 сентября 2008

В Vista, для процесса, который не запускается от имени администратора, для назначения окна из другого процесса, он должен:

  • Вставить файл манифеста с uiAccess = "true" (пример ниже)
  • Цифровая подпись приложения
  • Установите и запустите его из «безопасного» места, например «Program Files»

Вот пример манифеста:

<?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>
1 голос
/ 25 августа 2011

Мой ответ (исходя из моего опыта) относительно функции Windows API :: GetWindowRgn (...)

Эта функция не работает в Vista и Windows 7, то есть возвращает ERROR.

Но эта функция хорошо работает в Windows XP.

Поэтому я бы посоветовал следующее несложное решение: Если вы используете эту функцию в ожидаемом приложении под другой Windows предоставьте тест как это: int nResultOfRgnOperation = :: GetWindowRegion (...); if (nResultOfRgnOperation! = ОШИБКА) <Использовать далее всю область окна, определенную этой функцией> еще <Найдите ограничительный прямоугольник для всего окна и используйте далее этот ограничивающий прямоугольник вместо области окна. В случае необходимости вы можете создать прямоугольную область, которая представляет ограничивающий прямоугольник. >

Пожалуйста, используйте соответствующий код в местах, отмеченных выше как <...>

Спасибо за ваш энтузиазм.


1 голос
/ 28 сентября 2008

Вы упоминаете, что пытаетесь получить область окна другого процесса . Vista усилила безопасность многих межпроцессных вызовов Win32. Я не могу найти какую-либо документацию так или иначе для GetWindowRgn(), но вы можете проверить это достаточно просто. Сделайте простой проект, который устанавливает свой собственный регион, и попробуйте использовать свое оригинальное приложение, чтобы получить регион простого приложения. Если это работает, то это будет раздражать, и люди не смогут использовать ваше приложение ни с чем. Если это не сработает, есть вероятность, что ваше приложение вообще не будет работать в Vista.

...