[python-win32] Reading IMMDevice friendly name using property store

Stefan Boskovic boskovicstefan95 at gmail.com
Thu Apr 27 04:04:01 EDT 2023


Hi,

I'm trying to enumerate audio devices and access their friendly names with
python like in this example
<https://learn.microsoft.com/en-us/windows/win32/coreaudio/device-properties>.
I've expanded on volume control example
<https://www.mail-archive.com/python-win32@python.org/msg10282.html> from
the mail archive by Tim Roberts, I've added necessary methods to
IMMDeviceEnumerator,
redefined OpenPropertyStore() method in IMMDevice interface. Problem seems
to be in IPropertyStore interface when defining its methods, specifically
the GetValue method. I cannot find PropertyKey structure like PROPERTYKEY
structure from windows SDK (propsys.h), so I tried defining my own, and I
hope I'm using the correct type for PROPVARIANT argument. Also, I'm not
sure where are constants like  PKEY_Device_FriendlyName defined?

```
from comtypes import GUID, Structure, HRESULT, COMMETHOD, STDMETHOD,
IUnknown, c_float, CoCreateInstance, CLSCTX_ALL
from ctypes import POINTER
from ctypes.wintypes import DWORD, BOOL, UINT, LPWSTR
from win32comext.propsys import propsys

# from: C:\Program Files (x86)\Windows
Kits\10\Include\10.0.18362.0\um\functiondiscoverykeys_devpkey.h
PKEY_Device_FriendlyName = 0xa45c254e
CLSID_MMDeviceEnumerator = \
    GUID('{BCDE0395-E52F-467C-8E3D-C4579291692E}')


class PropertyKey(Structure):
    _fields_ = [("fmtid", GUID),
                ("pid", DWORD)]


REFPROPERTYKEY = PropertyKey
PROPVARIANT = propsys.PROPVARIANTType


class IAudioEndpointVolume(IUnknown):
    _iid_ = GUID('{5CDF2C82-841E-4546-9722-0CF74078229A}')
    _methods_ = [
        STDMETHOD(HRESULT, 'RegisterControlChangeNotify', []),
        STDMETHOD(HRESULT, 'UnregisterControlChangeNotify', []),
        STDMETHOD(HRESULT, 'GetChannelCount', []),
        COMMETHOD([], HRESULT, 'SetMasterVolumeLevel',
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')
                  ),
        COMMETHOD([], HRESULT, 'SetMasterVolumeLevelScalar',
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')
                  ),
        COMMETHOD([], HRESULT, 'GetMasterVolumeLevel',
                  (['out', 'retval'], POINTER(c_float), 'pfLevelDB')
                  ),
        COMMETHOD([], HRESULT, 'GetMasterVolumeLevelScalar',
                  (['out', 'retval'], POINTER(c_float), 'pfLevelDB')
                  ),
        COMMETHOD([], HRESULT, 'SetChannelVolumeLevel',
                  (['in'], DWORD, 'nChannel'),
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')
                  ),
        COMMETHOD([], HRESULT, 'SetChannelVolumeLevelScalar',
                  (['in'], DWORD, 'nChannel'),
                  (['in'], c_float, 'fLevelDB'),
                  (['in'], POINTER(GUID), 'pguidEventContext')
                  ),
        COMMETHOD([], HRESULT, 'GetChannelVolumeLevel',
                  (['in'], DWORD, 'nChannel'),
                  (['out', 'retval'], POINTER(c_float), 'pfLevelDB')
                  ),
        COMMETHOD([], HRESULT, 'GetChannelVolumeLevelScalar',
                  (['in'], DWORD, 'nChannel'),
                  (['out', 'retval'], POINTER(c_float), 'pfLevelDB')
                  ),
        COMMETHOD([], HRESULT, 'SetMute',
                  (['in'], BOOL, 'bMute'),
                  (['in'], POINTER(GUID), 'pguidEventContext')
                  ),
        COMMETHOD([], HRESULT, 'GetMute',
                  (['out', 'retval'], POINTER(BOOL), 'pbMute')
                  ),
        COMMETHOD([], HRESULT, 'GetVolumeStepInfo',
                  (['out', 'retval'], POINTER(c_float), 'pnStep'),
                  (['out', 'retval'], POINTER(c_float), 'pnStepCount'),
                  ),
        COMMETHOD([], HRESULT, 'VolumeStepUp',
                  (['in'], POINTER(GUID), 'pguidEventContext')
                  ),
        COMMETHOD([], HRESULT, 'VolumeStepDown',
                  (['in'], POINTER(GUID), 'pguidEventContext')
                  ),
        COMMETHOD([], HRESULT, 'QueryHardwareSupport',
                  (['out', 'retval'], POINTER(DWORD),
'pdwHardwareSupportMask')
                  ),
        COMMETHOD([], HRESULT, 'GetVolumeRange',
                  (['out', 'retval'], POINTER(c_float), 'pfMin'),
                  (['out', 'retval'], POINTER(c_float), 'pfMax'),
                  (['out', 'retval'], POINTER(c_float), 'pfIncr')
                  ),

    ]


class IPropertyStore(IUnknown):
    _iid_ = GUID('{886d8eeb-8cf2-4446-8d02-cdba1dbdcf99}')
    _methods_ = [
        COMMETHOD([], HRESULT, 'GetCount',
                  (['out'], POINTER(DWORD), 'cProps')
                  ),
        COMMETHOD([], HRESULT, 'GetAt',
                  (['in'], DWORD, 'iProp'),
                  (['out'], POINTER(PropertyKey), 'pkey')
                  ),
        COMMETHOD([], HRESULT, 'GetValue',
                  (['in'], REFPROPERTYKEY, 'key'),
                  (['out', 'retval'], PROPVARIANT, 'pv')
                  ),
        STDMETHOD('SetValue', HRESULT, [])
    ]
    pass


class IMMDevice(IUnknown):
    _iid_ = GUID('{D666063F-1587-4E43-81F1-B948E807363F}')
    _methods_ = [
        COMMETHOD([], HRESULT, 'Activate',
                  (['in'], POINTER(GUID), 'iid'),
                  (['in'], DWORD, 'dwClsCtx'),
                  (['in'], POINTER(DWORD), 'pActivationParams'),
                  (['out', 'retval'],
POINTER(POINTER(IAudioEndpointVolume)), 'ppInterface')
                  ),
        COMMETHOD([], HRESULT, 'OpenPropertyStore',
                  (['in'], DWORD, 'stgmAccess'),
                  (['out', 'retval'], POINTER(POINTER(IPropertyStore)),
'ppProperties')
                  ),
        COMMETHOD([], HRESULT, 'GetId',
                  (['out', 'retval'], POINTER(LPWSTR), 'ppstrId')
                  ),
        STDMETHOD(HRESULT, 'GetState', [])
    ]
    pass


class IMMDeviceCollection(IUnknown):
    _iid_ = GUID('{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}')
    _methods_ = [
        COMMETHOD([], HRESULT, 'GetCount',
                  (['out', 'retval'], POINTER(UINT), 'pcDevices')
                  ),
        COMMETHOD([], HRESULT, 'Item',
                  (['in'], UINT, 'nDevice'),
                  (['out', 'retval'], POINTER(POINTER(IMMDevice)),
'ppDevice')
                  )
    ]
    pass


class IMMDeviceEnumerator(IUnknown):
    _iid_ = GUID('{A95664D2-9614-4F35-A746-DE8DB63617E6}')

    _methods_ = [
        COMMETHOD([], HRESULT, 'EnumAudioEndpoints',
                  (['in'], DWORD, 'dataFlow'),
                  (['in'], DWORD, 'dwStateMask'),
                  (['out', 'retval'],
POINTER(POINTER(IMMDeviceCollection)), 'ppDevices')
                  ),
        COMMETHOD([], HRESULT, 'GetDefaultAudioEndpoint',
                  (['in'], DWORD, 'dataFlow'),
                  (['in'], DWORD, 'role'),
                  (['out', 'retval'], POINTER(POINTER(IMMDevice)),
'ppDevices')
                  )
    ]


enumerator = CoCreateInstance(
    CLSID_MMDeviceEnumerator,
    IMMDeviceEnumerator,
    CLSCTX_ALL
)


def print_device_details(device):
    device_id = device.GetId()
    print(device_id)
    device.OpenPropertyStore(0)


devices = enumerator.EnumAudioEndpoints(0, 1)
device_count = devices.GetCount()
print('device_count', device_count)
for i in range(device_count):
    device = devices.Item(i)
    print_device_details(device)
```

Regards,
Stefan Boskovic
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.python.org/pipermail/python-win32/attachments/20230427/a3834988/attachment.html>


More information about the python-win32 mailing list