Всех приветствую!
Помогите портировать код чтения IPropertyStore. Мучаю следующий пример:
Получилось подключиться к устройству по умолчанию и считать настройки.
Но как дело доходит до чтения $sPKEY_AudioEngine_DeviceFormat, типа данных PROPVARIANT, которая содержит структуру WAVEFORMATEXTENSIBLE,
возвращается 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
возвращается 0.
Помогите пожалуйста, как правильно считать эти параметры.