Я многому научился, находясь в поисках ответа на этот вопрос.Во время квеста я упал в кроличью нору ( Приключения Алисы в стране чудес Чарльза Лютвиджа Доджсона, также известного как Льюис Кэрролл), только чтобы найти Ктулху ( Зов Ктулху от Лавкрафта), ожидающегоme.
Мои первоначальные исследования привели меня к следующим макросам, определенным в afxwin.h.
- DECLARE_INTERFACE_MAP
- BEGIN_INTERFACE_MAP
- END_INTERFACE_MAP
- BEGIN_INTERFACE_PART
- END_INTERFACE_PART
Лучшая документация, которую я мог найти для этих макросов, содержится в TN038: Реализация MFC / OLE IUnknown техническое примечание.Хорошим примером, демонстрирующим использование этих макросов и реализацию функции QueryService, является пример TstCon .
Конечно, это привело к другому вопросу, какое окно мне нужно для этогоза?Чтобы ответить на этот вопрос, я посмотрел исходный код определенной программы чтения с экрана, чтобы увидеть, как он использует интерфейс IAccessibleApplication.
Следующая функция, хотя и не фактический используемый код, демонстрирует метод (я не могу поделиться фактическимкод, поскольку программа чтения с экрана не является открытым исходным кодом).
std::wstring GetApplicationNameUsingTheIAccessibleApplicationInterface(
HWND hwnd, long idObject, long idChild)
{
CComPtr<IAccessible> acc;
CComVariant var;
auto hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &acc, &var);
if (hr != S_OK) return L"";
if (!acc) return L"";
CComQIPtr<IServiceProvider> serviceProvider = acc;
if (!serviceProvider) return L"";
CComQIPtr<IAccessibleApplication> application;
hr = serviceProvider->QueryService(
IID_IAccessible, __uuidof(IAccessibleApplication),
reinterpret_cast<void**>(&application));
if (FAILED(hr)) return L"";
if (!application) return L"";
CComBSTR appName;
hr = application->get_appName(&text);
if (FAILED(hr)) return L"";
return appName.m_str;
}
Эта функция или что-то подобное вызывается из нашей функции обратного вызова WinEventProc *1033* в ответ на событие EVENT_OBJECT_FOCUS.Это указывает на то, что мне нужно делать это для каждого окна, которое может получить фокус.
Вооружившись тем, что, по моему мнению, было ответом на мой вопрос, я углубился и реализовал интерфейс IAccessibleApplication и добавил необходимый код ко всеммои фокусируемые окна.К моему большому сожалению, моя функция QueryService никогда не вызывалась.Когда я отладил программу чтения с экрана, чтобы выяснить, почему, я обнаружил, что неявный QueryInterface, подразумеваемый следующей строкой кода, не удался.
CComQIPtr<IServiceProvider> serviceProvider = acc;
Это привело к долгим и трудным квестам, чтобы выяснить, почему вызов QueryInterfaceтерпел неудачу.
Сначала я работал над личным проектом, поэтому я не мог использовать ресурсы, имеющиеся у моего работодателя.Затем, совершенно случайно, мне была поручена задача, которая требовала от меня предоставления информации о том, как реализовать интерфейс IAccessible2 в приложении C ++, клиенту, который нуждался в информации, чтобы помочь им сделать свои приложения более доступными.Ура, я наконец-то смог обратиться к коллегам за помощью!
Мой коллега вел меня по правильному пути.
- Создайте настроенную версию класса IAccessibleProxyImpl и класса CAccessibleProxy с использованием источникакод, полученный из atlacc.h.
- Добавьте COM_INTERFACE_ENTRY для IAccessibleApplication в COM_MAP ( BEGIN_COM_MAP / END_COM_MAP ) для моего пользовательского класса IAccessibleProxyImpl.
- Используйте макросы BEGIN_SERVICE_MAP, END_SERVICE_MAP и SERVICE_ENTRY для обеспечения реализации интерфейса IServiceProvider.
- Предоставьте переопределение для функции CWnd :: CreateAccessibleProxy , чтобы заставить мои окна использовать мой настраиваемый доступный прокси-сервер и, следовательно, мою реализацию интерфейса IAccessibleApplication.
Теперь программа чтения с экрана использует имя приложения, которое я предоставляю для интерфейса IAccessibleApplication для моего приложения.
Приложение, для которого я сделал этос открытым исходным кодом.Это мое TTSApp приложение.Я также привел пример, который демонстрирует, как использовать подобную технику для поддержки интерфейса IAccessible2, доступного здесь .
Я делюсь этим в надежде, что информация окажется полезной.