Консольное приложение против приложения Win32 - перечисление устройств захвата DirectSound дает разные результаты

Я ищу надежный метод для сопоставления GUID устройства захвата DirectShow с его соответствующим значением waveID.

Я нашел следующий проект Chris_P:

Решение прекрасно работает, и оно опирается на довольно IKsPropertySet Интерфейс для получения сопоставления.

К сожалению, если я попробую ту же технику из библиотеки C++/CLI, код завершится неудачно с E_NOTIMPL (это поведение было описано по этому вопросу, - см. ответ Владимира Хмелёва)

Итак, я подумал, что мог бы написать простое вспомогательное приложение на основе консоли для извлечения отображений и их печати. Моя библиотека могла бы затем запустить это вспомогательное приложение и проанализировать перенаправленный вывод, чтобы получить сопоставления.

Консольная программа работает нормально, однако GUID, которые передаются обратному вызову перечисления, полностью отличаются от тех, которые передаются решением Chris_P.

На самом деле все они имеют одинаковую базовую структуру:

lpGuid = 0x02ad0808 {BDF35A00-B9AC-11D0-A619-00AA00A7C000}

Единственное изменение происходит в последних цифрах GUID, где, по совпадению, они соответствуют отображенному значению waveId.

Еще одна странная вещь заключается в том, что описание устройства захвата усекается до 31 символа, как если бы перечисление выполнялось с помощью API-интерфейсов WaveIn!

Казалось бы, какой-то фасад DirectSound теперь оборачивает WaveIn API.

Какие-нибудь указатели на то, что могло бы случиться?, Могу ли я отключить это поведение и перечислить те же GUIDS, что перечисляет приложение WIN32?

Вот код для консольного приложения:

#include "stdafx.h"
#include <mmreg.h>
#include <initguid.h>
#include <Dsound.h>
#include <dsconf.h>


static BOOL CALLBACK DSEnumCallback(
   LPGUID  lpGuid,
   LPCTSTR  lpcstrDescription,
   LPCTSTR  lpcstrModule,
   LPVOID  lpContext
);

static BOOL GetInfoFromDSoundGUID(GUID i_sGUID, DWORD &dwWaveID);
static HRESULT DirectSoundPrivateCreate(OUT LPKSPROPERTYSET * ppKsPropertySet);

typedef WINUSERAPI HRESULT(WINAPI *LPFNDLLGETCLASSOBJECT) (const CLSID &, const IID &, void **);



BOOL GetInfoFromDSoundGUID(GUID i_sGUID, DWORD &dwWaveID) {
   LPKSPROPERTYSET         pKsPropertySet = NULL;
   HRESULT                 hr;
   BOOL                 retval = FALSE;

   PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA psDirectSoundDeviceDescription = NULL;
   DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA sDirectSoundDeviceDescription;

   memset(&sDirectSoundDeviceDescription, 0, sizeof(sDirectSoundDeviceDescription));
   hr = DirectSoundPrivateCreate(&pKsPropertySet);
   if( SUCCEEDED(hr) ) {
      ULONG ulBytesReturned = 0;
      sDirectSoundDeviceDescription.DeviceId = i_sGUID;

      // On the first call the final size is unknown so pass the size of the struct in order to receive
      // "Type" and "DataFlow" values, ulBytesReturned will be populated with bytes required for struct+strings.
      hr = pKsPropertySet->Get(DSPROPSETID_DirectSoundDevice,
                               DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION,
                               NULL,
                               0,
                               &sDirectSoundDeviceDescription,
                               sizeof(sDirectSoundDeviceDescription),
                               &ulBytesReturned
      );

      if( ulBytesReturned ) {
         // On the first call it notifies us of the required amount of memory in order to receive the strings.
         // Allocate the required memory, the strings will be pointed to the memory space directly after the struct.
         psDirectSoundDeviceDescription = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA)new BYTE[ulBytesReturned];
         *psDirectSoundDeviceDescription = sDirectSoundDeviceDescription;

         hr = pKsPropertySet->Get(DSPROPSETID_DirectSoundDevice,
                                  DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION,
                                  NULL,
                                  0,
                                  psDirectSoundDeviceDescription,
                                  ulBytesReturned,
                                  &ulBytesReturned
         );

         dwWaveID = psDirectSoundDeviceDescription->WaveDeviceId;
         delete[] psDirectSoundDeviceDescription;
         retval = TRUE;
      }

      pKsPropertySet->Release();
   }

   return retval;
}



HRESULT DirectSoundPrivateCreate(OUT LPKSPROPERTYSET * ppKsPropertySet) {
   HMODULE                 hLibDsound = NULL;
   LPFNDLLGETCLASSOBJECT   pfnDllGetClassObject = NULL;
   LPCLASSFACTORY          pClassFactory = NULL;
   LPKSPROPERTYSET         pKsPropertySet = NULL;
   HRESULT                 hr = DS_OK;

   // Load dsound.dll 
   hLibDsound = LoadLibrary(TEXT("dsound.dll"));

   if( !hLibDsound ) {
      hr = DSERR_GENERIC;
   }

   // Find DllGetClassObject 
   if( SUCCEEDED(hr) ) {
      pfnDllGetClassObject =
         (LPFNDLLGETCLASSOBJECT)GetProcAddress(hLibDsound, "DllGetClassObject");


      if( !pfnDllGetClassObject ) {
         hr = DSERR_GENERIC;
      }
   }

   // Create a class factory object     
   if( SUCCEEDED(hr) ) {
      hr = pfnDllGetClassObject(CLSID_DirectSoundPrivate, IID_IClassFactory, (LPVOID *)&pClassFactory);
   }

   // Create the DirectSoundPrivate object and query for an IKsPropertySet 
   // interface 
   if( SUCCEEDED(hr) ) {
      hr = pClassFactory->CreateInstance(NULL, IID_IKsPropertySet, (LPVOID *)&pKsPropertySet);
   }

   // Release the class factory 
   if( pClassFactory ) {
      pClassFactory->Release();
   }

   // Handle final success or failure 
   if( SUCCEEDED(hr) ) {
      *ppKsPropertySet = pKsPropertySet;
   } else if( pKsPropertySet ) {
      pKsPropertySet->Release();
   }

   FreeLibrary(hLibDsound);

   return hr;
}




BOOL CALLBACK DSEnumCallback(
   LPGUID  lpGuid,
   LPCTSTR  lpcstrDescription,
   LPCTSTR  lpcstrModule,
   LPVOID  lpContext
) {



   LPWSTR psz = NULL;
   StringFromCLSID(*lpGuid, &psz);
   DWORD WaveID = 0xFFFFFFFF;

   if( lpGuid ) {
      GUID i_guid = *lpGuid;
      GetInfoFromDSoundGUID(i_guid, WaveID);
   }

   if( WaveID != 0xFFFFFFFF ) 
      wprintf(_T("%d %s\r\n"), WaveID, psz);

   if( psz ) {
      CoTaskMemFree(psz);
   }

   return TRUE;
}


int main()
{
    DirectSoundCaptureEnumerate(DSEnumCallback, NULL);
    Sleep(10000);
    return 0;
}

1 ответ

Решение

Оказывается, я не инициализировал COM.

Я добавил следующий фрагмент в начале моего main() Процедура и программа получили ожидаемые идентификаторы GUID:

   HRESULT hr = NULL;
   hr = CoInitialize(NULL);
   if( FAILED(hr) ) {
      printf("Failed to initialize COM");
      return -1;
   }

Поэтому я предполагаю, что если COM не инициализирован, механизм DirectSound возвращается к API WaveIn (создавая фасад DirectShow вокруг него).

Другие вопросы по тегам