waveOutGetDevCaps、Win7 和长设备名称

发布于 2024-10-19 06:27:54 字数 154 浏览 1 评论 0原文

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

Win7 的做法是什么?

I'm maintaining an old code base that's using waveOutGetDevCaps to get the names of the audio devices on the system. On Windows 7 machines this results in truncated names, as WAVEOUTCAPS.szPname is limited by MAXPNAMELEN (31 chars).

What's the Win7 way of doing this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

轻拂→两袖风尘 2024-10-26 06:27:54

您可以使用核心音频 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 设备相关联。

You could use one of the Core Audio APIs:

// 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);
}       

Error handling was removed in the above code to make it more readable. (I happen to love using C++/CLI to move between C# and the Windows APIs.)

Now the harder part will be to relate the endpoint names to the MME devices in your old code base.

若言繁花未落 2024-10-26 06:27:54

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

适用于 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;

I have found another way using the registry to find audio devices' full name, both Input and Output.

Works on Windows 7 and 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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文