0

以下是我PROPVARIANT使用 WASAPI API 相关函数获取结构的方法:

//Pointer for stored audio stream
IAudioClient *iac = NULL;

//Endpoint device selection
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDevice *pDevice;
IMMDeviceCollection *pCollection = NULL;
CoInitialize(NULL);
hr = CoCreateInstance(
    CLSID_MMDeviceEnumerator, NULL,
    CLSCTX_ALL, IID_IMMDeviceEnumerator,
    (void**)&pEnumerator);

hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pCollection);

//Create vector of IMMDevices
UINT endpointCount = NULL;
(*pCollection).GetCount(&endpointCount);
std::vector<IMMDevice**> IMMDevicePP;   //IMMDevice seems to contain all endpoint devices, so why have a collection here?
for (UINT i = 0; i < (endpointCount); i++)
{
    IMMDevice* pp = NULL;
    (*pCollection).Item(i, &pp);
    IMMDevicePP.assign(1, &pp);
}
UINT IMMDeviceCount = IMMDevicePP.size();

//Enumerate Properties of IMMDevices
std::vector<IPropertyStore*> IMMDeviceProperties;
for (int k = 0; k < IMMDeviceCount; k++) {
    IPropertyStore* prop = NULL;
    (**IMMDevicePP[k]).OpenPropertyStore(STGM_READ, &prop);
    IMMDeviceProperties.assign(1, prop);
}
UINT PropertyStoreCount = IMMDeviceProperties.size();

//Find name property of device
std::vector<PROPVARIANT*> properties;
for (int i = 0; i < PropertyStoreCount; i++) {
    DWORD propCount = 1;
    HRESULT countResult = (*IMMDeviceProperties[i]).GetCount(&propCount);
    if (countResult == S_OK) { }
    else {
        int x = 5;
    }
    for (int p = 0; p < propCount; p++) {
        PROPERTYKEY key;
        HRESULT keyResult = (*IMMDeviceProperties[i]).GetAt(p, &key);
        HRESULT getAT;
        PROPVARIANT propVari;
        HRESULT propVariResult = (*IMMDeviceProperties[i]).GetValue(key, &propVari);
        propVari.vt = VT_LPWSTR;
        LPWSTR test = propVari.pwszVal;
        //char pwszValTest;
        //strcpy(&pwszValTest, propVari.pwszVal);
        //WCHAR friendlyName = *propVari.pwszVal;
        properties.assign(1, &propVari);
    }
}

全部HRESULT返回 S_OK。

PROPVARIANT乍一看,生成的结构正确呈现。但是,当使用 VS 的属性 watch 进一步检查时,所有字符串类型属性都会返回此问题标题中反映的错误。因此,当我尝试检索包含我的结构pwszVal属性的音频端点设备的名称时,如下所示:PROPVARIANT

LPWSTR test = propVari.pwszVal;

我无法检索所需的数据。我尝试使用各种转换器方法复制字符串无济于事。我知道这个错误有很多问题,但我似乎无法破解这个错误。

这是文档PROPVARIANT及其相应的属性:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa380072(v=vs.85).aspx

在本文档中,它声明“PROPVARIANT成员vt设置为VT_LPWSTRVT_LPWSTR是一种枚举类型,对应于值 31。而 VT_BLOB 对应于值 65。我的vt成员被设置为VT_BLOBor 65 而不是 31 or VT_LPWSTR。为什么会这样?这与本文档中所述的值相矛盾:

http://msdn.microsoft.com/en-us/library/windows/desktop/dd370812(v=vs.85).aspx

手动设置vt成员也不会更改/修复字符串读取错误:

propVari.vt = VT_LPWSTR;

PKEY_Device_FriendlyName就是我所追求的。非常感谢任何帮助/提示。

4

2 回答 2

1

您没有正确填充向量。您正在存储局部变量的内存地址,而不是变量引用的实际项目。

更糟糕的是,您正在使用std::vector::assign()添加项目。 assign()用指定的值替换向量的全部内容。如果您在一个集合中有多个设备,那么您最终不会得到多个设备的向量。您应该使用push_back()而不是assign().

您在使用所有向量时都犯了这些错误。

在旁注中,您应该在调用对象的方法时使用->运算符而不是使用。(*).它将使代码更清晰,更易于阅读。

试试这个:

//Endpoint device selection
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDeviceCollection *pCollection = NULL;

CoInitialize(NULL);
hr = CoCreateInstance(
    CLSID_MMDeviceEnumerator, NULL,
    CLSCTX_ALL, IID_IMMDeviceEnumerator,
    (void**)&pEnumerator);

hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pCollection);
pEnumerator->Release();

//Create vector of IMMDevices
std::vector<IMMDevice*> IMMDevice;
UINT endpointCount = 0;
hr = pCollection->GetCount(&endpointCount);
if (hr == S_OK) {
    IMMDevice.reserve(endpointCount);
    for (UINT i = 0; i < endpointCount; ++i) {
        IMMDevice *pDevice = NULL;
        hr = pCollection->Item(i, &pDevice);
        if (hr == S_OK) {
            IMMDevice.push_back(pDevice);
        }
    }
}
UINT IMMDeviceCount = IMMDevice.size();

pCollection->Release();

//Enumerate Properties of IMMDevices
std::vector<IPropertyStore*> IMMDeviceProperties;
IMMDeviceProperties.reserve(IMMDeviceCount);
for (int k = 0; k < IMMDeviceCount; k++) {
    IPropertyStore* prop = NULL;
    hr = IMMDevice[k]->OpenPropertyStore(STGM_READ, &prop);
    if (hr == S_OK) {
        IMMDeviceProperties.push_back(prop);
    }
}
UINT PropertyStoreCount = IMMDeviceProperties.size();

//Find name property of devices
std::vector<std::wstring> MMDeviceFriendlyNames;
MMDeviceFriendlyNames.reserve(IMMDeviceCount);
for (int i = 0; i < PropertyStoreCount; i++) {
    PROPVARIANT propVari;
    PropVariantInit(&propVari);
    hr = IMMDeviceProperties[i]->GetValue(PKEY_Device_FriendlyName, &propVari);
    if (hr == S_OK) {
        MMDeviceFriendlyNames.push_back(propVari.pwszVal);
        PropVariantClear(&propVari);
    }
}

// use vectors as needed...

for (UINT i = 0; i < PropertyStoreCount; ++i) {
    IMMDeviceProperties[i]->Release();
}
for (UINT i = 0; i < IMMDeviceCount; ++i) {
    IMMDevice[i]->Release();
}
于 2014-10-02T23:38:54.633 回答
1

以下代码基于您的代码但没有混淆向量似乎可以正常工作。在运行它时,我得到“FriendlyName:Speakers / HP (IDT High Definition Audio CODEC)”,这对于这台笔记本电脑来说似乎是正确的。

当使用 COM 并且没有某种智能指针时,要非常小心地释放所有指针。并始终检查所有结果。COM 调用可能由于各种原因而失败。

#define WINVER _WIN32_WINNT_VISTA
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define STRICT
#include <windows.h>
#include <ole2.h>
#include <mmdeviceapi.h>
#include <propsys.h>
#include <propvarutil.h>
#include <stdio.h>
#include <Functiondiscoverykeys_devpkey.h>

#pragma comment(lib, "ole32")
#pragma comment(lib, "propsys")

const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);

static HRESULT
DumpDeviceProperties(IMMDevice *pDevice)
{
    IPropertyStore *pStore = NULL;
    HRESULT hr = pDevice->OpenPropertyStore(STGM_READ, &pStore);
    if (SUCCEEDED(hr))
    {
        PROPVARIANT prop;
        PropVariantInit(&prop);
        hr = pStore->GetValue(PKEY_Device_FriendlyName, &prop);
        if (SUCCEEDED(hr))
        {
            if (IsPropVariantString(prop))
                wprintf(L"FriendlyName: %s\n", PropVariantToStringWithDefault(prop, L"(missing)"));
            else
                hr = E_UNEXPECTED;
        }
        PropVariantClear(&prop);
        pStore->Release();
    }
    return hr;
}

int
wmain(int argc, WCHAR *argv[])
{
    HRESULT hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
    if (SUCCEEDED(hr))
    {
        IMMDeviceEnumerator *pEnumerator = NULL;
        hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, reinterpret_cast<void **>(&pEnumerator));
        if (SUCCEEDED(hr))
        {
            IMMDeviceCollection *pCollection = NULL;
            hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pCollection);
            if (SUCCEEDED(hr))
            {
                UINT cEndpoints = 0;
                hr = pCollection->GetCount(&cEndpoints);
                if (SUCCEEDED(hr))
                {
                    for (UINT n = 0; SUCCEEDED(hr) && n < cEndpoints; ++n)
                    {
                        IMMDevice *pDevice = NULL;
                        hr = pCollection->Item(n, &pDevice);
                        if (SUCCEEDED(hr))
                        {
                            hr = DumpDeviceProperties(pDevice);
                            pDevice->Release();
                        }
                    }
                }
                pCollection->Release();
            }
            pEnumerator->Release();
        }
        CoUninitialize();
    }
    return SUCCEEDED(hr) ? 0 : 1;
}

编译使用:cl -nologo -MDd -Zi -W3 -Od lsdevices.cpp使用 MSVC 2013。

于 2014-10-02T23:41:35.967 回答