EreTIk's Box » Cтатьи, исходники » Установка устройства аудио-воспроизведения по умолчанию, используя недокументированный COM-интерфейс IPolicyConfig


В настоящее время ситуация, когда на машине установлено несколько звуковых плат, уже редкостью не назовешь. Вот и я, став обладателем "внешнего" телевизора, который подключается через HDMI, для своего ноутбука, стал активно пользоваться установкой устройства аудио-воспроизведения по умолчанию. Как оказалось, единственный доступный способ переключить устройство аудио-воспроизведения - MmSys.cpl.


Постоянно вызывать свойства звуковых устройств это не решение. Поэтому я решил написать небольшую утилиту DefSound. Основное назначение - висеть в системном трее и переключать устройство по-умолчанию.


Как выяснилось, установить устройство воспроизведения по умолчанию документированным способом не возможно. Пришлось вооружиться стандартным боекомплектом: IDA и WinDBG. Тестовой системой выступила Windows Vista.


Для начала статически анализируем дизассемблированный листинг MmSys.cpl. Немного поковырявшись, приходим к методу CEndpoint::MakeDefault. Это метод отвечает за обработку события установки пользователем нового аудиоустройства по умолчанию. Метод инициирует ATL'ное получение COM-интерфейса :


push    17h             ; dwClsContext
push    0               ; pUnkOuter
; CLSID запрашиваемого интерфейса
push    offset __GUID_294935CE_F637_4E7C_A41B_AB255460B862
lea     ecx, [ebp+var_10]
; вызов ATL::CComPtrBase<IPolicyConfig>::CoCreateInstance(_GUID const &,IUnknown *,ulong)
call    1CD32850h
                

Из приведенного листинга мы получаем интересующий нас CLSID: GUID{294935CE-F637-4E7C-A41B-AB255460B862}. Но для получения COM-интерфейса также необходим IID, его мы с легкостью получим, посмотрев дизассемблированный листинг метода ATL::CComPtrBase::IPolicyConfig::CoCreateInstance :


mov     [ebp+ppv], ecx
mov     eax, [ebp+ppv]
push    eax             ; ppv
; IID запрашиваемого интерфейса
push    offset __GUID_568b9108_44bf_40b4_9006_86afe5b5a620 ; riid
mov     ecx, [ebp+dwClsContext]
push    ecx             ; dwClsContext
mov     edx, [ebp+pUnkOuter]
push    edx             ; pUnkOuter
mov     eax, [ebp+rclsid]
push    eax             ; rclsid
; вызов ole32!CoCreateInstance(...)
call    ds:__imp__CoCreateInstance@20

                

Вот мы и добрались до ole32!CoCreateInstance(...). Тем самым получаем интересующий нас идентификатор интерфейса IID: GUID{568b9108-44bf-40b4-9006-86afe5b5a620}.


Полученных данных не достаточно, так как мы все еще не можем восстановить список виртуальных методов интерфейса. Поэтому продолжаем трассировку метода CEndpoint::MakeDefault и приходим к вызову метода полученного интерфейса.


В итоге трассировки мы попадаем в метод CPolicyConfigClient::SetDefaultEndpoint, реализованный в динамической библиотеке AudioSes.dll.


Загружаем динамическую библиотеку AudioSes.dll в IDA, и получаем искомый символ ATL::CComObject<class CPolicyConfigClient>::`vftable': таблицу виртуальных функций интерфейса IPolicyConfig


На основе вышеописанного небольшого исследования я написал небольшую утилиту DefSound, которая позволяет по правой кнопке мыши, в выпадающем меню, выбрать устройство аудио-воспроизведения по умолчанию.


Updated (22.09.2010)


Получив отзыв об этом небольшом исследовании от Robert Bacs, я обнаружил, что часть методов IPolicyConfig на Windows 7 возвращают ERROR_NOT_SUPPORTED(0x32). Беглое дизассемблирование показало, что на в Windows 7 класс IPolicyConfig переименован в IPolicyConfigVista, соответственно CPolicyConfigClient переименован в CPolicyConfigVistaClient. Этот интерфейс присутствует на обоих ОС (Vista и 7) и метод SetDefaultEndpoint(...) успешно работает, поэтому утилита DefSound оказалась работоспособной на обеих версиях ОС.


Продолжив, я нашел новый интерфейс CLSID: GUID{870af99c-171d-4f9e-af0d-e63df40c2bc9} и IID: GUID{f8679f50-850a-41cf-9c72-430f290290c8}, который в Windows 7 называется IPolicyConfig. Я тоже решил перейти к новому именованию интерфейсов. В IPolicyConfig реализованы методы, которые в интерфейсе CPolicyConfigVistaClient на Windows 7 возвращают ERROR_NOT_SUPPORTED:

  • GetMixFormat(...)
  • GetProcessingPeriod(...)
  • SetProcessingPeriod(...)
  • GetShareMode(...)
  • SetShareMode(...)
  • SetEndpointVisibility(...)

Следовательно, эти методы стоит использовать следующим образом: на Windows Vista, где IPolicyConfig не зарегистрирован, необходимо вызвать эти методы у интерфейса IPolicyConfigVista. На ОС Windows 7 эти методы необходимо вызывать из IPolicyConfig.


Из вышесказанного, я дополнил заголовочный файл PolicyConfig.h, в котором старый интерфейс имеет суффикс Vista и присутствует новый интерфейс IPolicyConfig, доступный только в Windows 7.


Скачать утилиту DefSound и исходные тексты к ней.


ΞρεΤΙκ