waveOutGetDevCaps,Win7和长设备名称

问题描述 投票:0回答:2

我正在维护一个旧代码库,它使用waveOutGetDevCaps来获取系统上音频设备的名称。在Windows 7计算机上,这会导致名称被截断,因为WAVEOUTCAPS.szPname受MAXPNAMELEN(31个字符)的限制。

Win7的做法是什么?

windows-7 audio
2个回答
0
投票

您可以使用其中一个Core Audio API:

// get the device enumerator
IMMDeviceEnumerator* pEnumerator = NULL;
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
                              CLSCTX_ALL,__uuidof(IMMDeviceEnumerator),
                              (void**)&pEnumerator);

// get the endpoint collection
IMMDeviceCollection* pCollection = NULL;
DWORD mask = DEVICE_STATE_ACTIVE || DEVICE_STATE_UNPLUGGED;
hr = pEnumerator->EnumAudioEndpoints(eRender, mask, &pCollection);

// get the size of the collection
UINT count = 0;
hr = pCollection->GetCount(&count);

for (int i = 0; i < (int)count; i++)
{
    // get the endpoint
    IMMDevice* pEndPoint = NULL;
    hr = pCollection->Item(i, &pEndPoint);

    // get the human readable name
    String^ friendlyName;
    IPropertyStore* pProps = NULL;
    HRESULT hr = pEndPoint->OpenPropertyStore(STGM_READ, &pProps);
    PROPVARIANT varName;
    PropVariantInit(&varName);
    hr = pProps->GetValue(PKEY_Device_FriendlyName, &varName);
    friendlyName = gcnew String(varName.pwszVal);
    PropVariantClear(&varName);
}       

在上面的代码中删除了错误处理,使其更具可读性。 (我喜欢使用C ++ / CLI在C#和Windows API之间移动。)

现在,更难的部分是将端点名称与旧代码库中的MME设备相关联。


0
投票

我找到了另一种使用注册表查找音频设备全名的方法,包括输入和输出。

适用于Windows 7和Windows 10。

procedure TForm_Config.FormCreate(Sender: TObject);
type
  tagWAVEOUTCAPS2A = packed record
    wMid: WORD;
    wPid: WORD;
    vDriverVersion: MMVERSION;
    szPname: array[0..MAXPNAMELEN-1] of AnsiChar;
    dwFormats: DWORD;
    wChannels: WORD;
    wReserved1: WORD;
    dwSupport: DWORD;
    ManufacturerGuid: System.TGUID;
    ProductGuid: System.TGUID;
    NameGuid: System.TGUID;
  end;
var
  i,outdevs: Integer;
  woCaps: tagWAVEOUTCAPS2A;
  RegistryService: TRegistry;
  iClasses, iSubClasses, iNames: Integer;
  audioDeviceClasses, audioDeviceSubClasses, audioDeviceNames: TStringList;
  initialDeviceName, partialDeviceName, fullDeviceName: string;
begin
  audioDeviceClasses := TStringList.Create;
  audioDeviceSubClasses := TStringList.Create;
  audioDeviceNames := TStringList.Create;
  try
    RegistryService := TRegistry.Create;
    try
      RegistryService.RootKey := HKEY_LOCAL_MACHINE;
      if RegistryService.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Enum\HDAUDIO\') then begin
        RegistryService.GetKeyNames(audioDeviceClasses);
        RegistryService.CloseKey();
        for iClasses := 0 to audioDeviceClasses.Count - 1 do begin
          if RegistryService.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Enum\HDAUDIO\'+audioDeviceClasses[iClasses]) then begin
            RegistryService.GetKeyNames(audioDeviceSubClasses);
            RegistryService.CloseKey();
            for iSubClasses := 0 to audioDeviceSubClasses.Count - 1 do begin
              if RegistryService.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Enum\HDAUDIO\'+audioDeviceClasses[iClasses]+'\'+audioDeviceSubClasses[iSubClasses]) then begin
                if RegistryService.ValueExists('DeviceDesc') then begin
                  fullDeviceName := Trim(RegistryService.ReadString('DeviceDesc'));
                  if AnsiPos(';',fullDeviceName) > 0 then begin
                    fullDeviceName := Trim(AnsiMidStr(fullDeviceName, AnsiPos(';',fullDeviceName)+1, Length(fullDeviceName)));
                  end;
                  audioDeviceNames.Add(fullDeviceName);
                end;
                RegistryService.CloseKey();
              end;
            end;
          end;
        end;
      end;
    finally
      FreeAndNil(RegistryService);
    end;

    // WaveOutDevComboBox is a selection box (combo) placed in the form and will receive the list of output audio devices
    WaveOutDevComboBox.Clear;

    try
      outdevs := waveOutGetNumDevs;
      for i := 0 to outdevs - 1 do begin
        ZeroMemory(@woCaps, sizeof(woCaps));
        if waveOutGetDevCaps(i, @woCaps, sizeof(woCaps)) = MMSYSERR_NOERROR then begin
          RegistryService := TRegistry.Create;
          try
            RegistryService.RootKey := HKEY_LOCAL_MACHINE;
            if RegistryService.OpenKeyReadOnly('\System\CurrentControlSet\Control\MediaCategories\' + GUIDToString(woCaps.NameGuid)) then begin
              WaveOutDevComboBox.Items.Add(RegistryService.ReadString('Name'));
              RegistryService.CloseKey();
            end
            else begin
              initialDeviceName := '';
              partialDeviceName := Trim(woCaps.szPname);
              if AnsiPos('(',partialDeviceName) > 0 then begin
                initialDeviceName := Trim(AnsiLeftStr(partialDeviceName,AnsiPos('(',partialDeviceName)-1));
                partialDeviceName := Trim(AnsiMidStr(partialDeviceName,AnsiPos('(',partialDeviceName)+1,Length(partialDeviceName)));
                if AnsiPos(')',partialDeviceName) > 0 then begin
                  partialDeviceName := Trim(AnsiLeftStr(partialDeviceName,AnsiPos(')',partialDeviceName)-1));
                end;
              end;
              for iNames := 0 to audioDeviceNames.Count - 1 do begin
                fullDeviceName := audioDeviceNames[iNames];
                if AnsiStartsText(partialDeviceName,fullDeviceName) then begin
                  break;
                end
                else begin
                  fullDeviceName := partialDeviceName;
                end;
              end;
              WaveOutDevComboBox.Items.Add(initialDeviceName + IfThen(initialDeviceName<>EmptyStr,' (','') + fullDeviceName + IfThen(initialDeviceName<>EmptyStr,')',''));
            end;
          finally
            FreeAndNil(RegistryService);
          end;
        end;
      end;
    except
      WaveOutDevComboBox.Enabled := False;
    end;
  finally
    FreeAndNil(audioDeviceClasses);
    FreeAndNil(audioDeviceSubClasses);
    FreeAndNil(audioDeviceNames);
  end;
end;
© www.soinside.com 2019 - 2024. All rights reserved.