2017-01-19 5 views
1

Я использую доступность с помощью функции AccessibleObjectFromPoint, и я бы хотел, чтобы она работала правильно в среде DPI для монитора. К сожалению, я не могу заставить его работать. Я пробовал много вещей, и ситуация на данный момент составляет:AccessibleObjectFromPoint и per-monitor DPI

  • Мое приложение помечено как per-monitor-DPI-aware в манифесте. (True/PM)
  • Я использую GetCursorPos, а затем AccessibleObjectFromPoint.

Как воспроизвести проблему:

  • Есть два монитора, один с 100% DPI, другой 125%.
  • Запустите Chrome на мониторе 125%.
  • Используйте AccessibleObjectFromPoint на одном из названий вкладок, это не сработает.

Он работает с некоторыми приложениями (как и у DPI, похоже, как проводник), но не работает с другими. Я пробовал несколько соответствующих функций, таких как GetPhysicalCursorPos и PhysicalToLogicalPointForPerMonitorDPI, но ничего не работает.

Стоит отметить, что Microsoft inspect.exe работает должным образом.

+0

ли OS 8.1, 10.0.10240, 10.0.10586 или 10.0.14393. Апи продолжает меняться. При победе 7 все работало над физическими координатами. У меня был код, который работал на 10586, который разбивается на 14393. Если окно максимизировано, вы можете получить информацию о мониторе, вычесть исходное изображение монитора и умножить на dpi, разделенные на dpi. Затем добавьте источник монитора. Это работает на 14393, если окно максимально. У меня такая же проблема, и я все еще расследую. – birdwes

+0

Причина, по которой я упоминаю три версии Windows 10, например, вызов API Win32 GetDpiForWindow() доступен только с 14393 года. Клиенты моего клиента имеют версии LTS 10.0.10240 и 10.0.10586, поэтому они все еще находятся в дикой природе, по крайней мере, в течение многих месяцев. Поэтому мне пришлось написать .NET-обертку в C++/CLI, которая работает со всем от Vista до 10.0.14393. Загрузите User32.dll и Shcore.dll динамически во время выполнения и потяните указатели на функции (или NULL), чтобы выяснить, какой вариант ОС вы выполняете, и соответствующим образом реагируйте. – birdwes

+0

P.S. Начиная с 14393 года и узнавая нить DPI, использование манифеста теперь не в моде. См. Https://msdn.microsoft.com/en-us/library/windows/desktop/dn302122(v=vs.85).aspx Вызов SetProcessDpiAwareness, если включен 8.1+ или SetProcessDPIAware(), если на Win 7 или Vista. – birdwes

ответ

1

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

Проблема началась с Windows 8.1. Проблема не существовала в Windows 7 или Vista, потому что AccessibleObjectFromPoint всегда использовал необработанные физические координаты, как описано здесь: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317984(v=vs.85).aspx.
«Microsoft Active Accessibility не использует логические координаты. Следующие методы и функции либо возвращают физические координаты, либо принимают их как параметры ». Это не соответствует действительности с Windows 8.1.

Доступно с помощью функции UseObjectFromPoint используется неверный расчет, который не всегда может найти правильное окно по причинам, аналогичным моему вопросу: High DPI scaling, mouse hooks and WindowFromPoint. Мои выводы привели меня к одному выводу: API сломан. Это не значит, что это невозможно.

Возможные решения Я частично опробовал, что, похоже, следует за ними. Предпосылкой является то, что вы

1 /. Сделайте свой процесс на каждом мониторе DPI, НЕ ИСПОЛЬЗУЙТЕ МАНИФЕСТ (подробнее об этом позже).

2 /. Определите hWnd окна, которое вы хотите запросить (варианты WindowFromPoint())

3 /. Определите монитор DPI запрошенного hWnd

4 /. Определите DPI вашего процесса

5 /. Определите DPI запрошенного hWnd

6 /.Определить происхождение монитора и смещение для запрашиваемой HWND (MonitorFromWindow() и GetMonitorInfo())

Далее, в зависимости от вашей платформы

Окно 10.0.14393+

Написать функцию, которая находит IAccessible (AccessibleObjectFromWindow()) из окна верхнего уровня, а затем рекурсивно вызовите метод IAccessible :: accHitTest, пока вы не достигнете самых нижних данных IAccessible и, возможно, ChildID. Верните это так, как если бы вы вызывали AccessibleObjectFromPoint.

Чтобы успешно его назвать, вам нужно будет масштабировать координаты (x, y) в системе масштабирования запрошенного hWnd, используя DPI и координаты, выбранные в списке выше. Следите за системами, в которых мониторы не имеют одинакового размера, или если мониторы частично смещены или выше и ниже.

И теперь для важной части для 10.0.14393 - Установите поток к тому же DPI_AWARENESS_CONTEXT hWnd, который вы запрашиваете. Теперь вызовите новую функцию. Теперь верните поток, чтобы отслеживать DPI, и он работает, даже если окно не максимизировано. Вот почему вы не должны использовать манифест.

Если вы находитесь на Windows От 8.1 до 10.0.10586 у вас есть более сложная задача. Вместо вызова функции accHitTest, как указано выше, вы должны рекурсивно вызывать AccessChildren и перебирать вызов IAccessible :: accLocation, чтобы определить, находится ли ваша контрольная точка внутри каждого дочернего элемента. Это сложно и начинает становиться действительно беспорядочным, когда вы достигаете, например, комбинированные поля в таких продуктах, как Office, который является только системным DPI.

Это все, что я могу вам дать сейчас.

Чтобы сделать это успешно на многоплатформенной платформе (моя работа должна работать от Vista до Windows-Current), единственная действительно безопасная ставка заключается в том, чтобы написать DLL-оболочку на C++, которая во время выполнения может определить, на какой ОС она включена, и изменить код путь соответственно. Причина, по которой вы хотите сделать это на C++, заключается в том, чтобы не пропускать объекты IAccessible через границу .Net/unmanaged marshalling. Вы можете вызвать IUnknown :: Release на объекты, которые вам не нужны, чтобы вернуть неуправляемую сторону. Вы можете сделать все это в .Net, но это будет медленно.

P.S. также следите за тем, чтобы Chrome возвращал бесконечные деревья, где родители являются родителями своих родителей, требуются некоторые проверки на змей. Кроме того, Chrome не возвращает accRole правильно и даст вам HTML-теги вместо VT_I4.

Успехов

+0

P.S. Тесты, которые я сделал в .Net vs C++, находятся в области 20-50 раз быстрее на C++. – birdwes

 Смежные вопросы

  • Нет связанных вопросов^_^