Что нового

Чтение, запись в IPropertyStore, помогите портировать код из Си.

VadimKHL

Новичок
Сообщения
155
Репутация
0
Всех приветствую!
Помогите портировать код чтения IPropertyStore. Мучаю следующий пример:
C:
#define INITGUID
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <Objbase.h>
#include <Shobjidl.h>
#include <MMDeviceAPI.h>
#include <locale.h>
#include <Functiondiscoverykeys_devpkey.h>

//Используемые библиотеки: winmm.lib;strmiids.lib;quartz.lib;uuid.lib

int _tmain(int argc, _TCHAR* argv[])
{
    setlocale(LC_ALL,"Russian");

    CoInitialize(NULL);
    TCHAR* pstr=NULL;
    DWORD state;

    IMMDeviceEnumerator *deviceEnumerator = NULL;
    IMMDeviceCollection *deviceCollection = NULL;
    IMMDevice* dev=NULL;
    IPropertyStore *propertyStore=NULL;
    WAVEFORMATEX wex;//буфер для данных о формате

    HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceEnumerator));
    if(FAILED(hr)) {printf("CoCreateInstance fail: HRESULT 0x%x",hr);goto End;}


    hr = deviceEnumerator->EnumAudioEndpoints(eRender,  DEVICE_STATE_ACTIVE, &deviceCollection);
    if(FAILED(hr)) {printf("EnumAudioEndpoints fail: HRESULT 0x%x",hr);goto End;}

    UINT deviceCount;
    hr = deviceCollection->GetCount(&deviceCount);
    if(FAILED(hr)) {printf("GetCount fail: HRESULT 0x%x",hr);goto End;}

    //display all endpoints
    for (UINT DeviceIndex = 0 ; DeviceIndex < deviceCount; DeviceIndex++)
    {
        deviceCollection->Item(DeviceIndex,&dev);
        if(FAILED(hr)) {printf("Item fail: 0x%x\n",hr);goto Next;}

        dev->GetId(&pstr);
        if(FAILED(hr)) {printf("Can't get device ID: HRESULT 0x%x",hr);goto Next;}

        hr = dev->OpenPropertyStore(STGM_READ, &propertyStore);     
        if(FAILED(hr)) {printf("Can't open property store: HRESULT 0x%x",hr);goto Next;}

        PROPVARIANT friendlyName;
        PropVariantInit(&friendlyName);

        hr = propertyStore->GetValue(PKEY_Device_FriendlyName, &friendlyName);     
        if(FAILED(hr)) {printf("Can't get device name: HRESULT 0x%x",hr);goto Next;}

        printf("\n");
        wprintf(friendlyName.pwszVal);
        printf("\n");
        PropVariantClear(&friendlyName);

        printf("Device id: ");
        wprintf(pstr);
        printf("\n");       

        dev->GetState(&state);
        if(FAILED(hr)) {printf("Can't get state: HRESULT 0x%x",hr);goto Next;}
        printf("State: %d\n",state);

        PROPVARIANT format;
        PropVariantInit(&format);

        hr = propertyStore->GetValue(PKEY_AudioEngine_DeviceFormat, &format);
        if(FAILED(hr)) {printf("Can't get format: HRESULT 0x%x",hr);goto Next;}

        printf("\n* Audio Format: *\n");       
        memcpy_s(&wex,sizeof(wex),format.blob.pBlobData,sizeof(wex));//копировать данные формата в буфер
        printf("Format tag: 0x%x\n",(int)wex.wFormatTag);
        printf("Channels: %d\n",(int)wex.nChannels);
        printf("Bits per sample: %d\n",(int)wex.wBitsPerSample);
        printf("Frequency: %d\n",(int)wex.nSamplesPerSec);
        printf("Block align: %d\n",(int)wex.nBlockAlign);
        PropVariantClear(&format);

        /* ****************** */

Next:   if(dev!=NULL){dev->Release();dev=NULL;}
        if(propertyStore!=NULL){propertyStore->Release();propertyStore=NULL;}

    }//end for


End:if(dev!=NULL){dev->Release();dev=NULL;}
    if(propertyStore!=NULL){propertyStore->Release();propertyStore=NULL;}
    if(deviceEnumerator!=NULL){deviceEnumerator->Release();deviceEnumerator=NULL;}
    if(deviceCollection!=NULL){deviceCollection->Release();deviceCollection=NULL;} 

    CoUninitialize();
    system("PAUSE");
    return 0;
}

Получилось подключиться к устройству по умолчанию и считать настройки.
Код:
; Audio Endpoint Properties.
; https://learn.microsoft.com/en-gb/windows/win32/coreaudio/audio-endpoint-properties
Global Const $sPKEY_AudioEndpoint_FormFactor                = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E}, 0"
Global Const $sPKEY_AudioEndpoint_ControlPanelPageProvider  = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E}, 1"
Global Const $sPKEY_AudioEndpoint_Association               = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E}, 2"
Global Const $sPKEY_AudioEndpoint_PhysicalSpeakers          = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E}, 3"
Global Const $sPKEY_AudioEndpoint_GUID                      = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E}, 4"
Global Const $sPKEY_AudioEndpoint_Disable_SysFx             = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E}, 5"
Global Const $sPKEY_AudioEndpoint_FullRangeSpeakers         = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E}, 6"
Global Const $sPKEY_AudioEndpoint_Supports_EventDriven_Mode = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E}, 7"
Global Const $sPKEY_AudioEndpoint_JackSubType               = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E}, 8"
Global Const $sPKEY_AudioEngine_DeviceFormat                = "{F19F064D-082C-4E27-BC73-6882A1BB8E4C}, 0"
Global Const $sPKEY_AudioEngine_OEMFormat                   = "{E4870E26-3CC5-4CD2-BA46-CA0A9A70ED04}, 3"

; Device Properties (Core Audio APIs).
; https://learn.microsoft.com/en-gb/windows/win32/coreaudio/device-properties
Global Const $sPKEY_DeviceInterface_FriendlyName = "{026E516E-B814-414B-83CD-856D6FEF4822}, 2"
Global Const $sPKEY_Device_DeviceDesc            = "{A45C254E-DF1C-4EFD-8020-67D146A850E0}, 2"
Global Const $sPKEY_Device_FriendlyName          = "{A45C254E-DF1C-4EFD-8020-67D146A850E0}, 14"
Global Const $sPKEY_Device_InstanceId            = "{78C34FC8-104A-4ACA-9EA4-524D52996E57}, 256"
Global Const $sPKEY_Device_ContainerId           = "{8C7ED206-3F8A-4827-B3AB-AE9E1FAEFC6C}, 2"

; IMMDeviceEnumerator interface.
; https://learn.microsoft.com/en-us/windows/win32/api/mmdeviceapi/nn-mmdeviceapi-immdeviceenumerator
Global Const $sCLSID_IMMDeviceEnumerator = "{BCDE0395-E52F-467C-8E3D-C4579291692E}"
Global Const $sIID_IMMDeviceEnumerator = "{A95664D2-9614-4F35-A746-DE8DB63617E6}"
Global Const $tagIMMDeviceEnumerator = "EnumAudioEndpoints hresult(dword;dword;ptr*);" & _
                                       "GetDefaultAudioEndpoint hresult(dword;dword;ptr*);" & _
                                       "GetDevice hresult(wstr;ptr*);" & _
                                       "RegisterEndpointNotificationCallback hresult(ptr);" & _
                                       "UnregisterEndpointNotificationCallback hresult(ptr)"

; IMMDevice interface.
; https://learn.microsoft.com/en-us/windows/win32/api/mmdeviceapi/nn-mmdeviceapi-immdevice
Global Const $sIID_IMMDevice = "{D666063F-1587-4E43-81F1-B948E807363F}"
Global Const $tagIMMDevice = "Activate hresult(clsid;dword;variant*;ptr*);" & _
                             "OpenPropertyStore hresult(dword;ptr*);" & _
                             "GetId hresult(wstr*);" & _
                             "GetState hresult(dword*)"

; IAudioEndpointVolume interface.
; https://learn.microsoft.com/en-us/windows/win32/api/endpointvolume/nn-endpointvolume-iaudioendpointvolume
Global Const $sIID_IAudioEndpointVolume = "{5CDF2C82-841E-4546-9722-0CF74078229A}"
Global Const $tagIAudioEndpointVolume = "RegisterControlChangeNotify hresult(ptr);" & _
                                        "UnregisterControlChangeNotify hresult(ptr);" & _
                                        "GetChannelCount hresult(uint*);" & _
                                        "SetMasterVolumeLevel hresult(float;ptr);" & _
                                        "SetMasterVolumeLevelScalar hresult(float;ptr);" & _
                                        "GetMasterVolumeLevel hresult(float*);" & _
                                        "GetMasterVolumeLevelScalar hresult(float*);" & _
                                        "SetChannelVolumeLevel hresult(uint;float;ptr);" & _
                                        "SetChannelVolumeLevelScalar hresult(uint;float;ptr);" & _
                                        "GetChannelVolumeLevel hresult(uint;float*);" & _
                                        "GetChannelVolumeLevelScalar hresult(uint;float*);" & _
                                        "SetMute hresult(int;ptr);" & _
                                        "GetMute hresult(int*);" & _
                                        "GetVolumeStepInfo hresult(uint*;uint*);" & _
                                        "VolumeStepUp hresult(ptr);" & _
                                        "VolumeStepDown hresult(ptr);" & _
                                        "QueryHardwareSupport hresult(dword*);" & _
                                        "GetVolumeRange hresult(float*;float*;float*)"

; IPropertyStore interface.
; https://learn.microsoft.com/en-us/windows/win32/api/propsys/nn-propsys-ipropertystore
Global Const $sIID_IPropertyStore = "{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}"
Global Const $tagIPropertyStore = "GetCount hresult(dword*);" & _
                                  "GetAt hresult(dword;ptr*);" & _
                                  "GetValue hresult(struct*;variant*);" & _
                                  "SetValue hresult(struct*;variant);" & _
                                  "Commit hresult();"

; STGM enumeration.
; https://learn.microsoft.com/en-us/windows/win32/stg/stgm-constants
Global Enum $STGM_READ = 0, $STGM_WRITE, $STGM_READWRITE

; CLSCTX enumeration.
; https://learn.microsoft.com/en-us/windows/win32/api/wtypesbase/ne-wtypesbase-clsctx
Global Const $CLSCTX_INPROC_SERVER                  = 0x1, _
             $CLSCTX_INPROC_HANDLER                 = 0x2, _
             $CLSCTX_LOCAL_SERVER                   = 0x4, _
             $CLSCTX_INPROC_SERVER16                = 0x8, _
             $CLSCTX_REMOTE_SERVER                  = 0x10, _
             $CLSCTX_INPROC_HANDLER16               = 0x20, _
             $CLSCTX_RESERVED1                      = 0x40, _
             $CLSCTX_RESERVED2                      = 0x80, _
             $CLSCTX_RESERVED3                      = 0x100, _
             $CLSCTX_RESERVED4                      = 0x200, _
             $CLSCTX_NO_CODE_DOWNLOAD               = 0x400, _
             $CLSCTX_RESERVED5                      = 0x800, _
             $CLSCTX_NO_CUSTOM_MARSHAL              = 0x1000, _
             $CLSCTX_ENABLE_CODE_DOWNLOAD           = 0x2000, _
             $CLSCTX_NO_FAILURE_LOG                 = 0x4000, _
             $CLSCTX_DISABLE_AAA                    = 0x8000, _
             $CLSCTX_ENABLE_AAA                     = 0x10000, _
             $CLSCTX_FROM_DEFAULT_CONTEXT           = 0x20000, _
             $CLSCTX_ACTIVATE_X86_SERVER            = 0x40000, _
             $CLSCTX_ACTIVATE_32_BIT_SERVER         = $CLSCTX_ACTIVATE_X86_SERVER, _
             $CLSCTX_ACTIVATE_64_BIT_SERVER         = 0x80000, _
             $CLSCTX_ENABLE_CLOAKING                = 0x100000, _
             $CLSCTX_APPCONTAINER                   = 0x400000, _
             $CLSCTX_ACTIVATE_AAA_AS_IU             = 0x800000, _
             $CLSCTX_RESERVED6                      = 0x1000000, _
             $CLSCTX_ACTIVATE_ARM32_SERVER          = 0x2000000, _
             $CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION = 0x4000000, _
             $CLSCTX_PS_DLL                         = 0x80000000
; With DCOM, CLSCTX_REMOTE_SERVER should be included.
Global Const $CLSCTX_ALL = BitOR($CLSCTX_INPROC_SERVER, $CLSCTX_INPROC_HANDLER, $CLSCTX_LOCAL_SERVER, $CLSCTX_REMOTE_SERVER)
Global Const $CLSCTX_SERVER = BitOr($CLSCTX_INPROC_SERVER, $CLSCTX_LOCAL_SERVER, $CLSCTX_REMOTE_SERVER)
; Global $CLSCTX_ALL = BitOR($CLSCTX_INPROC_SERVER, $CLSCTX_INPROC_HANDLER, $CLSCTX_LOCAL_SERVER)
; Global $CLSCTX_SERVER = BitOr(CLSCTX_INPROC_SERVER, CLSCTX_LOCAL_SERVER)

; EDataFlow enumeration.
; https://learn.microsoft.com/en-us/windows/win32/api/mmdeviceapi/ne-mmdeviceapi-edataflow
Global Enum $eRender = 0, $eCapture, $eAll, $EDataFlow_enum_count

; ERole enumeration.
; https://learn.microsoft.com/en-us/windows/win32/api/mmdeviceapi/ne-mmdeviceapi-erole
Global Enum $eConsole = 0, $eMultimedia, $eCommunications, $ERole_enum_count

; WAVEFORMATEX structure.
; https://learn.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-waveformatex
Global Const $tagWAVEFORMATEX = "word wFormatTag;" & _
                                "word nChannels;" & _
                                "dword nSamplesPerSec;" & _
                                "dword nAvgBytesPerSec;" & _
                                "word nBlockAlign;" & _
                                "word wBitsPerSample;" & _
                                "word cbSize"

; WAVEFORMATEXTENSIBLE structure.
; https://learn.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-waveformatextensible
Global Const $tagWAVEFORMATEXTENSIBLE = $tagWAVEFORMATEX & ";" & _
                                        "word wValidBitsPerSample;" & _
                                        "word wSamplesPerBlock;" & _
                                        "word wReserved;" & _
                                        "dword dwChannelMask;" & _
                                        "ulong Data1;" & _
                                        "ushort Data2;" & _
                                        "ushort Data3;" & _
                                        "byte Data4[8]"

_Main()
If @error Then ConsoleWrite("Error: " & @error)
Exit

Func _Main()
    Local $Read
    ; Создать объекты интерфеса IAudioEndpointVolume, IPropertyStore для устройства вывода звука по умолчанию.
    Local $oVolume = _GetIAudioEndpointVolumeObject($eRender, $eConsole, True, $STGM_READ)

    ; Чтение DeviceFriendlyName.
    $Read = _ReadPKEY($oVolume[1], $sPKEY_DeviceInterface_FriendlyName)
    If @error Then Return SetError(1, 0, 0)
    ConsoleWrite(@CRLF & "DeviceFriendlyName: " & $Read)

    ; Чтение FriendlyName.
    $Read = _ReadPKEY($oVolume[1], $sPKEY_Device_FriendlyName)
    If @error Then Return SetError(1, 0, 0)
    ConsoleWrite(@CRLF & "FriendlyName: " & $Read)

    ; Чтение DeviceDesc.
    $Read = _ReadPKEY($oVolume[1], $sPKEY_Device_DeviceDesc)
    If @error Then Return SetError(1, 0, 0)
    ConsoleWrite(@CRLF & "DeviceDesc: " & $Read)

    ; Чтение PhysicalSpeakers.
    $Read = _ReadPKEY($oVolume[1], $sPKEY_AudioEndpoint_PhysicalSpeakers)
    If @error Then Return SetError(1, 0, 0)
    ConsoleWrite(@CRLF & "Mask PhysicalSpeakers: " & $Read)

    ; Чтение FullRangeSpeakers.
    $Read = _ReadPKEY($oVolume[1], $sPKEY_AudioEndpoint_FullRangeSpeakers)
    If @error Then Return SetError(2, 0, 0)
    ConsoleWrite(@CRLF & "Mask FullRangeSpeakers: " & $Read)

    ; Чтение DeviceFormat.
    $Read = _ReadPKEY($oVolume[1], $sPKEY_AudioEngine_DeviceFormat)
    If @error Then Return SetError(2, 0, 0)
    ConsoleWrite(@CRLF & "DeviceFormat: " & $Read)

    ConsoleWrite(@CRLF)
EndFunc

; ===============================================================================================================================
; Функции чтения/записи PKEY.
; ===============================================================================================================================
Func _ReadPKEY($oIPS, $sPKEY, $pID = Default)
    Local $hr, $sRet, $tPKEY
    ; Создание структуры PKEY из строки.
    $tPKEY = DllStructCreate("byte GUID[16];dword PID;")
    DllCall("propsys.dll", "long", "PSPropertyKeyFromString", "wstr", $sPKEY, "struct*", $tPKEY)
    If @error Then Return SetError(@error, @extended, 0)
    If $pID <> Default Then DllStructSetData($tPKEY, "PID", $pID)
    ; Чтение.
    $hr = $oIPS.GetValue($tPKEY, $sRet)
    If $hr Then Return SetError(1, $hr, 0)
    Return $sRet
EndFunc

Func _WritePKEY($oIPS, $sPKEY, $val, $pID = Default)
    Local $hr, $tPKEY
    ; Создание структуры PKEY из строки.
    $tPKEY = DllStructCreate("byte GUID[16];dword PID;")
    DllCall("propsys.dll", "long", "PSPropertyKeyFromString", "wstr", $sPKEY, "struct*", $tPKEY)
    If @error Then Return SetError(@error, @extended, 0)
    If $pID <> Default Then DllStructSetData($tPKEY, "PID", $pID)
    ; Запись.
    $hr = $oIPS.SetValue($tPKEY, $val)
    If $hr Then Return SetError(1, $hr, 0)
EndFunc
; ===============================================================================================================================
; Создание объекта интерфейса IAudioEndpointVolume.
; ===============================================================================================================================
; При успешном выполнении возвращает массив со следующими объектами:
; [0] - IAudioEndpointVolume
; Если флаг $IPSOpen = True,
; [1] - IPropertyStore
; ===============================================================================================================================
Func _GetIAudioEndpointVolumeObject($EDF = $eRender, $ERLE = $eConsole, $IPSOpen = False, $STGM = $STGM_READ)
    Local $hr, $aObjects[1]
    If $IPSOpen Then ReDim $aObjects[2]
    ; IMMDeviceEnumerator.
    Local $oMMDeviceEnumerator = ObjCreateInterface($sCLSID_IMMDeviceEnumerator, $sIID_IMMDeviceEnumerator, $tagIMMDeviceEnumerator)
    If @error Then Return SetError(1, 0, 0)
    ; GetDefaultAudioEndpoint.
    Local $pDefaultDevice
    $hr = $oMMDeviceEnumerator.GetDefaultAudioEndpoint($EDF, $ERLE, $pDefaultDevice)
    If $hr Then Return SetError(2, $hr, 0)
    Local $oDefaultDevice = ObjCreateInterface($pDefaultDevice, $sIID_IMMDevice, $tagIMMDevice)
    If @error Then Return SetError(3, 0, 0)
    ; IAudioEndpointVolume.
    Local $pIAudioEndpointVolume
    $hr = $oDefaultDevice.Activate($sIID_IAudioEndpointVolume, $CLSCTX_ALL, 0, $pIAudioEndpointVolume)
    If $hr Then Return SetError(4, $hr, 0)
    Local $oIAudioEndpointVolume = ObjCreateInterface($pIAudioEndpointVolume, $sIID_IAudioEndpointVolume, $tagIAudioEndpointVolume)
    If @error Then Return SetError(5, 0, 0)
    ; IPropertyStore.
    If $IPSOpen Then
        Local $pProps
        $hr = $oDefaultDevice.OpenPropertyStore($STGM, $pProps)
        If $hr Then Return SetError(6, $hr, 0)
        Local $oProps = ObjCreateInterface($pProps, $sIID_IPropertyStore, $tagIPropertyStore)
        If @error Then Return SetError(7, 0, 0)
    EndIf
    ; Save objects to array and return.
    $aObjects[0] = $oIAudioEndpointVolume
    If $IPSOpen Then $aObjects[1] = $oProps
    Return $aObjects
EndFunc
Но как дело доходит до чтения $sPKEY_AudioEngine_DeviceFormat, типа данных PROPVARIANT, которая содержит структуру WAVEFORMATEXTENSIBLE,
возвращается 0.

Помогите пожалуйста, как правильно считать эти параметры.
 
Верх