Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

807 lines
22 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 - 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: devmap.cpp
  6. * Content: Maps various default devices GUIDs to real guids.
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 11-24-99 pnewson Created
  12. * 12-02-99 rodtoll Added new functions for mapping device IDs and finding default
  13. * devices.
  14. * rodtoll Updated mapping function to map default devices to real GUIDs
  15. * for non-DX7.1 platforms.
  16. * 01/25/2000 pnewson Added DV_MapWaveIDToGUID
  17. * 04/14/2000 rodtoll Bug #32341 GUID_NULL and NULL map to different devices
  18. * Updated so both map to default voice device
  19. * 04/19/2000 pnewson Error handling cleanup
  20. * 04/20/2000 rodtoll Bug #32889 - Unable to run on non-admin accounts on Win2k
  21. * 06/28/2000 rodtoll Prefix Bug #38022
  22. * rodtoll Whistler Bug #128427 - Unable to run voice wizard from multimedia control panel
  23. * 08/28/2000 masonb Voice Merge: Removed OSAL_* and dvosal.h, added STR_* and strutils.h
  24. * 01/08/2001 rodtoll WINBUG #256541 Pseudo: Loss of functionality: Voice Wizrd can't be launched.
  25. * 04/02/2001 simonpow Fixes for PREfast bugs #354859
  26. *
  27. ***************************************************************************/
  28. #include "dxvutilspch.h"
  29. #undef DPF_SUBCOMP
  30. #define DPF_SUBCOMP DN_SUBCOMP_VOICE
  31. #define REGSTR_WAVEMAPPER L"Software\\Microsoft\\Multimedia\\Sound Mapper"
  32. #define REGSTR_PLAYBACK L"Playback"
  33. #define REGSTR_RECORD L"Record"
  34. // function pointer typedefs
  35. typedef HRESULT (* PFGETDEVICEID)(LPCGUID, LPGUID);
  36. typedef HRESULT (WINAPI *DSENUM)( LPDSENUMCALLBACK lpDSEnumCallback,LPVOID lpContext );
  37. struct DSWaveDeviceFind_Param
  38. {
  39. GUID guidDevice;
  40. UINT uiDevice;
  41. UINT uiCounter;
  42. BOOL fCapture;
  43. };
  44. // DSWaveDeviceFind
  45. //
  46. // This callback function is used to try and match the GUID of the device to a
  47. // wave ID#. Once it finds the entry that matches the device GUID it determines
  48. // the waveIN ID by one of two methods:
  49. //
  50. // 1. Looks at the driver name, and looks for WaveIN X and uses X as the device ID.
  51. // (Only works on english versions). (WaveIN only)
  52. // 2. Fuzzy Matching - Order in enumeration determines device ID. The first device
  53. // which is not the default is device 0, second is device 1, etc.. etc...
  54. //
  55. #undef DPF_MODNAME
  56. #define DPF_MODNAME "DSWaveDeviceFind"
  57. BOOL CALLBACK DSWaveDeviceFind(
  58. LPGUID lpGUID,
  59. LPCTSTR lpszDesc,
  60. LPCTSTR lpszDrvName,
  61. LPVOID lpContext
  62. ) {
  63. DSWaveDeviceFind_Param *pParam = (DSWaveDeviceFind_Param *) lpContext;
  64. if( lpGUID == NULL )
  65. {
  66. DPFX(DPFPREP, DVF_INFOLEVEL, "Ignoring default" );
  67. return TRUE;
  68. }
  69. if( *lpGUID == pParam->guidDevice )
  70. {
  71. DPFX(DPFPREP, DVF_INFOLEVEL, "Device found id=%x", pParam->uiCounter );
  72. if( pParam->fCapture && sscanf( lpszDrvName, "WaveIn %u", &pParam->uiDevice ) == 1 )
  73. {
  74. DPFX(DPFPREP, DVF_INFOLEVEL, "Emulated Driver, Positive match found id=%d", pParam->uiDevice );
  75. }
  76. else
  77. {
  78. pParam->uiDevice = pParam->uiCounter;
  79. DPFX(DPFPREP, DVF_INFOLEVEL, "Fuzzy match found id=%d", pParam->uiDevice );
  80. }
  81. return TRUE;
  82. }
  83. pParam->uiCounter++;
  84. return TRUE;
  85. }
  86. // This function uses DSWaveDeviceFind to do a fuzzy map from GUID --> device ID on
  87. // old operating systems.
  88. //
  89. #undef DPF_MODNAME
  90. #define DPF_MODNAME "DV_LegacyFuzzyGUIDMap"
  91. HRESULT DV_LegacyFuzzyGUIDMap( BOOL fCapture, const GUID &guidDevice, DWORD *pdwDeviceID )
  92. {
  93. DSENUM enumFunc;
  94. HINSTANCE hinstds;
  95. DSWaveDeviceFind_Param findParam;
  96. HRESULT hr;
  97. hinstds = NULL;
  98. // Attempt to load the directsound DLL
  99. hinstds = LoadLibraryA( "DSOUND.DLL" );
  100. // If it couldn't be loaded, this sub system is not supported
  101. // on this system.
  102. if( hinstds == NULL )
  103. {
  104. DPFX(DPFPREP, DVF_INFOLEVEL, "Unable to load dsound.dll to enum devices" );
  105. return DVERR_GENERIC;
  106. }
  107. // Attempt to get the DirectSoundCaptureEnumerateA function from the
  108. // DSOUND.DLL. If it's not available then this class assumes it's
  109. // not supported on this system.
  110. if( fCapture )
  111. {
  112. #ifdef UNICODE
  113. enumFunc = (DSENUM) GetProcAddress( hinstds, "DirectSoundCaptureEnumerateW" );
  114. #else
  115. enumFunc = (DSENUM) GetProcAddress( hinstds, "DirectSoundCaptureEnumerateA" );
  116. #endif
  117. }
  118. else
  119. {
  120. #ifdef UNICODE
  121. enumFunc = (DSENUM) GetProcAddress( hinstds, "DirectSoundEnumerateW" );
  122. #else
  123. enumFunc = (DSENUM) GetProcAddress( hinstds, "DirectSoundEnumerateA" );
  124. #endif
  125. }
  126. if( enumFunc == NULL )
  127. {
  128. DPFX(DPFPREP, DVF_INFOLEVEL, "Unable to find enum func for enumerate" );
  129. FreeLibrary( hinstds );
  130. return DVERR_NOTSUPPORTED;
  131. }
  132. findParam.guidDevice = guidDevice;
  133. findParam.uiDevice = 0xFFFFFFFF;
  134. findParam.uiCounter = 0;
  135. findParam.fCapture = fCapture;
  136. hr = (*enumFunc)( DSWaveDeviceFind, &findParam );
  137. if( FAILED( hr ) )
  138. {
  139. DPFX(DPFPREP, DVF_INFOLEVEL, "Error enumerating capture devices hr = 0x%x", hr );
  140. }
  141. if( findParam.uiDevice == 0xFFFFFFFF )
  142. {
  143. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to map the capture device. Defaulting to 0" );
  144. *pdwDeviceID = 0;
  145. hr = DVERR_INVALIDDEVICE;
  146. }
  147. else
  148. {
  149. *pdwDeviceID = findParam.uiDevice;
  150. DPFX(DPFPREP, DVF_INFOLEVEL, "Found the device during enum, id=%d", findParam.uiDevice );
  151. }
  152. FreeLibrary( hinstds );
  153. return hr;
  154. }
  155. #undef DPF_MODNAME
  156. #define DPF_MODNAME "DV_CheckDeviceGUID"
  157. HRESULT DV_CheckDeviceGUID( BOOL fCapture, const GUID &guidDevice )
  158. {
  159. DWORD dwDeviceID;
  160. return DV_MapGUIDToWaveID( fCapture, guidDevice, &dwDeviceID );
  161. }
  162. // DV_MapGUIDToWaveID
  163. //
  164. // This function maps the specified GUID to the corresponding waveIN/waveOut device
  165. // ID. For default devices it looks up the system's default device, for other devices
  166. // it uses the private interface.
  167. //
  168. #undef DPF_MODNAME
  169. #define DPF_MODNAME "DV_MapGUIDToWaveID"
  170. HRESULT DV_MapGUIDToWaveID( BOOL fCapture, const GUID &guidDevice, DWORD *pdwDevice )
  171. {
  172. LPKSPROPERTYSET pPropertySet;
  173. PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA pData;
  174. GUID tmpGUID;
  175. HRESULT hr;
  176. // We're running on pre-private interface, no way to map default
  177. // device.
  178. if( guidDevice == GUID_NULL )
  179. {
  180. DPFX(DPFPREP, DVF_INFOLEVEL, "Mapping GUID to WaveID. Mapping GUID_NULL" );
  181. hr = DV_LegacyGetDefaultDeviceID( fCapture, pdwDevice );
  182. if( FAILED( hr ) )
  183. {
  184. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to determine default system waveIN ID hr = 0x%x", hr );
  185. }
  186. return hr;
  187. }
  188. DPFX(DPFPREP, DVF_INFOLEVEL, "Mapping non GUID_NULL to Wave ID" );
  189. hr = DirectSoundPrivateCreate( &pPropertySet );
  190. if( FAILED( hr ) )
  191. {
  192. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Unable to map GUID, attempting fuzzy map" );
  193. hr = DV_LegacyFuzzyGUIDMap( fCapture, guidDevice, pdwDevice );
  194. if( FAILED( hr ) )
  195. {
  196. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to map GUID to wave. Defaulting to ID 0 hr=0x%x", hr );
  197. *pdwDevice = 0;
  198. }
  199. }
  200. else
  201. {
  202. tmpGUID = guidDevice;
  203. hr = PrvGetDeviceDescription( pPropertySet, tmpGUID, &pData );
  204. if( FAILED( hr ) )
  205. {
  206. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to find GUID. Defaulting to ID 0 hr=0x%x", hr );
  207. }
  208. else
  209. {
  210. *pdwDevice = pData->WaveDeviceId;
  211. DPFX(DPFPREP, DVF_INFOLEVEL, "Mapped GUID to Wave ID %d", *pdwDevice );
  212. delete pData;
  213. }
  214. pPropertySet->Release();
  215. }
  216. return hr;
  217. }
  218. // DV_MapWaveIDToGUID
  219. //
  220. // This function maps the specified waveIN/waveOut device ID to the corresponding DirectSound
  221. // GUID.
  222. //
  223. #undef DPF_MODNAME
  224. #define DPF_MODNAME "DV_MapWaveIDToGUID"
  225. HRESULT DV_MapWaveIDToGUID( BOOL fCapture, DWORD dwDevice, GUID &guidDevice )
  226. {
  227. HRESULT hr;
  228. LPKSPROPERTYSET ppKsPropertySet;
  229. HMODULE hModule;
  230. hModule = LoadLibraryA( "dsound.dll " );
  231. if( hModule == NULL )
  232. {
  233. DPFX(DPFPREP, DVF_ERRORLEVEL, "Could not load dsound.dll" );
  234. return DVERR_GENERIC;
  235. }
  236. hr = DirectSoundPrivateCreate( &ppKsPropertySet );
  237. if( FAILED( hr ) )
  238. {
  239. FreeLibrary( hModule );
  240. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to get interface for ID<-->GUID Map hr=0x%x", hr );
  241. return hr;
  242. }
  243. if( DNGetOSType() == VER_PLATFORM_WIN32_NT )
  244. {
  245. WAVEINCAPSW wiCapsW;
  246. WAVEOUTCAPSW woCapsW;
  247. MMRESULT mmr;
  248. if( fCapture )
  249. {
  250. mmr = waveInGetDevCapsW( dwDevice, &wiCapsW, sizeof( WAVEINCAPSW ) );
  251. }
  252. else
  253. {
  254. mmr = waveOutGetDevCapsW( dwDevice, &woCapsW, sizeof( WAVEOUTCAPSW ) );
  255. }
  256. if( mmr != MMSYSERR_NOERROR )
  257. {
  258. DPFX(DPFPREP, DVF_ERRORLEVEL, "Specified device is invalid hr=0x%x", mmr );
  259. ppKsPropertySet->Release();
  260. FreeLibrary( hModule );
  261. return DVERR_INVALIDPARAM;
  262. }
  263. hr = PrvGetWaveDeviceMappingW( ppKsPropertySet, (fCapture) ? wiCapsW.szPname : woCapsW.szPname , fCapture, &guidDevice );
  264. }
  265. else
  266. {
  267. WAVEINCAPSA wiCapsA;
  268. WAVEOUTCAPSA woCapsA;
  269. MMRESULT mmr;
  270. if( fCapture )
  271. {
  272. mmr = waveInGetDevCapsA( dwDevice, &wiCapsA, sizeof( WAVEINCAPSA ) );
  273. }
  274. else
  275. {
  276. mmr = waveOutGetDevCapsA( dwDevice, &woCapsA, sizeof( WAVEOUTCAPSA ) );
  277. }
  278. if( mmr != MMSYSERR_NOERROR )
  279. {
  280. DPFX(DPFPREP, DVF_ERRORLEVEL, "Specified device is invalid hr=0x%x", mmr );
  281. ppKsPropertySet->Release();
  282. FreeLibrary( hModule );
  283. return DVERR_INVALIDPARAM;
  284. }
  285. hr = PrvGetWaveDeviceMapping( ppKsPropertySet, (fCapture) ? wiCapsA.szPname : woCapsA.szPname , fCapture, &guidDevice );
  286. }
  287. ppKsPropertySet->Release();
  288. if( FAILED( hr ) )
  289. {
  290. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to map ID-->GUID hr=0x%x", hr );
  291. }
  292. FreeLibrary( hModule );
  293. return hr;
  294. }
  295. // DV_GetDefaultDeviceID_Win2000
  296. //
  297. // Looks up the default waveIN or waveOut device ID for the system under
  298. // Windows 2000.
  299. //
  300. #undef DPF_MODNAME
  301. #define DPF_MODNAME "DV_GetDefaultDeviceID_Win2000"
  302. HRESULT DV_GetDefaultDeviceID_Win2000( BOOL fCapture, DWORD *pdwDeviceID )
  303. {
  304. MMRESULT mmr;
  305. DWORD dwFlags = 0;
  306. if( fCapture )
  307. {
  308. mmr = waveInMessage((HWAVEIN) ((UINT_PTR) WAVE_MAPPER), DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR) pdwDeviceID, (DWORD_PTR) &dwFlags);
  309. }
  310. else
  311. {
  312. mmr = waveOutMessage((HWAVEOUT) ((UINT_PTR) WAVE_MAPPER), DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR) pdwDeviceID, (DWORD_PTR) &dwFlags);
  313. }
  314. if( mmr != 0 )
  315. {
  316. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Unable to retrieve default device (Method A)" );
  317. }
  318. return CMixerLine::MMRESULTtoHRESULT(mmr);
  319. }
  320. // DV_GetDefaultWaveInID_Win2k
  321. //
  322. // Looks up the default waveIN or waveOut device ID for Win9x/Millenium
  323. // systems.
  324. //
  325. #undef DPF_MODNAME
  326. #define DPF_MODNAME "DV_GetDefaultWaveInID_Win2k"
  327. HRESULT DV_GetDefaultDeviceID_Win9X( BOOL fCapture, DWORD *pdwDeviceID )
  328. {
  329. CRegistry reg;
  330. wchar_t lpwszDeviceName[MAX_REGISTRY_STRING_SIZE+1];
  331. char lpszDeviceName[MAX_REGISTRY_STRING_SIZE+1];
  332. DWORD dwSize;
  333. DWORD dwIndex;
  334. UINT uiNumDevices;
  335. WAVEINCAPS wiCaps;
  336. WAVEOUTCAPS woCaps;
  337. MMRESULT mmr;
  338. HRESULT hr;
  339. if( !reg.Open( HKEY_CURRENT_USER, REGSTR_WAVEMAPPER, TRUE, FALSE ) )
  340. {
  341. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Unable to retrieve default device, cannot open (Method B)" );
  342. return DVERR_GENERIC;
  343. }
  344. dwSize = MAX_REGISTRY_STRING_SIZE+1;
  345. if( !reg.ReadString( fCapture ? REGSTR_RECORD : REGSTR_PLAYBACK, lpwszDeviceName, &dwSize ) )
  346. {
  347. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Unable to retrieve default device, cannot find (Method B)" );
  348. return DVERR_GENERIC;
  349. }
  350. if( fCapture )
  351. {
  352. uiNumDevices = waveInGetNumDevs();
  353. }
  354. else
  355. {
  356. uiNumDevices = waveOutGetNumDevs();
  357. }
  358. #if !defined(_UNICODE) && !defined(UNICODE)
  359. hr = STR_jkWideToAnsi( lpszDeviceName, lpwszDeviceName, MAX_REGISTRY_STRING_SIZE );
  360. if( FAILED( hr ) )
  361. {
  362. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Unable to convert device name ansi", lpszDeviceName );
  363. return hr;
  364. }
  365. #endif
  366. for( dwIndex = 0; dwIndex < uiNumDevices; dwIndex++ )
  367. {
  368. if( fCapture )
  369. {
  370. mmr = waveInGetDevCaps( dwIndex, &wiCaps, sizeof( WAVEINCAPS ) );
  371. }
  372. else
  373. {
  374. mmr = waveOutGetDevCaps( dwIndex, &woCaps, sizeof( WAVEOUTCAPS ) );
  375. }
  376. if( FAILED( mmr ) )
  377. {
  378. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Error querying device mmr=0x%x", mmr );
  379. }
  380. else
  381. {
  382. if( _tcscmp( (fCapture) ? wiCaps.szPname : woCaps.szPname, lpszDeviceName ) == 0 )
  383. {
  384. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Found default device, id=%d", dwIndex );
  385. *pdwDeviceID = dwIndex;
  386. return DV_OK;
  387. }
  388. }
  389. }
  390. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Unable to retrieve default device, could not match default device. (Method B)" );
  391. return DVERR_GENERIC;
  392. }
  393. // DV_LegacyGetDefaultDeviceID
  394. //
  395. // This function finds the default playback or capture device in the
  396. // system. (It's waveIN/waveOut device ID).
  397. //
  398. // This function will work on all Win9X platforms, Windows 2000.
  399. //
  400. // Not tested on Windows NT 4.0.
  401. //
  402. HRESULT DV_LegacyGetDefaultDeviceID( BOOL fCapture, DWORD *pdwDeviceID )
  403. {
  404. DNASSERT( pdwDeviceID != NULL );
  405. HRESULT hr;
  406. hr = DV_GetDefaultDeviceID_Win2000( fCapture, pdwDeviceID );
  407. if( FAILED( hr ) )
  408. {
  409. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Failed method A hr = 0x%x", hr );
  410. hr = DV_GetDefaultDeviceID_Win9X( fCapture, pdwDeviceID );
  411. if( FAILED( hr ) )
  412. {
  413. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Failed method B hr = 0x%x" , hr );
  414. return hr;
  415. }
  416. }
  417. return DV_OK;
  418. }
  419. // DV_LegacyMapDefaultGUID
  420. //
  421. // For systems that don't have DX7.1, determines the GUID for the default
  422. // playback or record devices. It does this by:
  423. //
  424. // 1. Looking up the system's default waveIn/waveOut ID
  425. // 2. Looking up the device's name
  426. // 3. Uses the private interface to map to a GUID
  427. //
  428. // This function will not work for systems without the private interface.
  429. //
  430. #undef DPF_MODNAME
  431. #define DPF_MODNAME "DV_LegacyMapDefaultGUID"
  432. HRESULT DV_LegacyMapDefaultGUID( BOOL fCapture, GUID* lpguidDevice)
  433. {
  434. DWORD dwDeviceID = 0;
  435. HRESULT hr = DV_OK;
  436. LPKSPROPERTYSET pPropertySet = NULL;
  437. WAVEINCAPS wiCaps;
  438. WAVEOUTCAPS woCaps;
  439. MMRESULT mmr = 0;
  440. hr = DV_LegacyGetDefaultDeviceID( fCapture, &dwDeviceID );
  441. if( FAILED( hr ) )
  442. {
  443. DPFX(DPFPREP, DVF_INFOLEVEL, "Could not determine default device ID hr=0x%x", hr );
  444. *lpguidDevice = GUID_NULL;
  445. return hr;
  446. }
  447. DPFX(DPFPREP, DVF_INFOLEVEL, "MapDefCapDev: Default device is device ID#%d", dwDeviceID );
  448. DPFX(DPFPREP, DVF_INFOLEVEL, "MapDefCapDev: Searching for matching GUID" );
  449. hr = DirectSoundPrivateCreate( &pPropertySet );
  450. if( FAILED( hr ) )
  451. {
  452. DPFX(DPFPREP, DVF_ERRORLEVEL, "MapDefCapDev: Unable to access search. (Defaulting to GUID_NULL) hr=0x%x", hr );
  453. *lpguidDevice = GUID_NULL;
  454. return hr;
  455. }
  456. if( fCapture )
  457. {
  458. mmr = waveInGetDevCaps( dwDeviceID, &wiCaps, sizeof( WAVEINCAPS ) );
  459. }
  460. else
  461. {
  462. mmr = waveOutGetDevCaps( dwDeviceID, &woCaps, sizeof( WAVEOUTCAPS ) );
  463. }
  464. if( FAILED( hr ) )
  465. {
  466. DNASSERT( FALSE );
  467. DPFX(DPFPREP, DVF_ERRORLEVEL, "MapDefCapDev: Retrieving device info failed default to GUID_NULL mmr=0x%x", mmr );
  468. pPropertySet->Release();
  469. *lpguidDevice = GUID_NULL;
  470. return CMixerLine::MMRESULTtoHRESULT( mmr );
  471. }
  472. hr = PrvGetWaveDeviceMapping( pPropertySet, (fCapture) ? wiCaps.szPname : woCaps.szPname, fCapture, lpguidDevice );
  473. if( FAILED( hr ) )
  474. {
  475. DPFX(DPFPREP, DVF_ERRORLEVEL, "MapDefCapDev: Unable to map from ID to GUID, defaulting to GUID_NULL hr=0x%x" , hr );
  476. *lpguidDevice = GUID_NULL;
  477. }
  478. pPropertySet->Release();
  479. return hr;
  480. }
  481. #undef DPF_MODNAME
  482. #define DPF_MODNAME "DV_MapCaptureDevice"
  483. HRESULT DV_MapCaptureDevice(const GUID* lpguidCaptureDeviceIn, GUID* lpguidCaptureDeviceOut)
  484. {
  485. LONG lRet;
  486. HRESULT hr;
  487. PFGETDEVICEID pfGetDeviceID;
  488. // attempt to map any default guids to real guids...
  489. HINSTANCE hDSound = LoadLibraryA("dsound.dll");
  490. if (hDSound == NULL)
  491. {
  492. lRet = GetLastError();
  493. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to get instance handle to DirectSound dll: %s", "dsound.dll");
  494. DPFX(DPFPREP, DVF_ERRORLEVEL, "LoadLibrary error code: %i", lRet);
  495. hr = DVERR_GENERIC;
  496. goto error_cleanup;
  497. }
  498. // attempt to get a pointer to the GetDeviceId function
  499. pfGetDeviceID = (PFGETDEVICEID)GetProcAddress(hDSound, "GetDeviceID");
  500. if (pfGetDeviceID == NULL)
  501. {
  502. lRet = GetLastError();
  503. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Unable to get a pointer to GetDeviceID function: %s", "GetDeviceID" );
  504. DPFX(DPFPREP, DVF_WARNINGLEVEL, "GetProcAddress error code: %i", lRet);
  505. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Assuming that we are running on a Pre-DX7.1 DirectSound", lRet);
  506. // On a pre-DX 7.1 system, we map NULL to GUID_NULL, and that's all, since
  507. // the other "default" guids don't really exist on this system (i.e. if I were
  508. // to pass them to DirectSound, it wouldn't understand.).
  509. if (lpguidCaptureDeviceIn == NULL ||
  510. *lpguidCaptureDeviceIn == DSDEVID_DefaultCapture ||
  511. *lpguidCaptureDeviceIn == DSDEVID_DefaultVoiceCapture ||
  512. *lpguidCaptureDeviceIn == GUID_NULL )
  513. {
  514. hr = DV_LegacyMapDefaultGUID( TRUE, lpguidCaptureDeviceOut );
  515. if( FAILED( hr ) )
  516. {
  517. DNASSERT( FALSE );
  518. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to perform old mapping. Assuming GUID_NULL" );
  519. *lpguidCaptureDeviceOut = GUID_NULL;
  520. }
  521. }
  522. else
  523. {
  524. *lpguidCaptureDeviceOut = *lpguidCaptureDeviceIn;
  525. }
  526. }
  527. else
  528. {
  529. // Use the GetDeviceID function to map the devices.
  530. if (lpguidCaptureDeviceIn == NULL)
  531. {
  532. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Warning: Mapping null device pointer to DSDEVID_DefaultCapture");
  533. lpguidCaptureDeviceIn = &DSDEVID_DefaultCapture;
  534. }
  535. else if (*lpguidCaptureDeviceIn == GUID_NULL)
  536. {
  537. // GetDeviceID does not accept GUID_NULL, since it does not know
  538. // if we are asking for a capture or playback device. So we map
  539. // GUID_NULL to the system default capture device here. Then
  540. // GetDeviceID can map it to the real device.
  541. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Warning: Mapping GUID_NULL to DSDEVID_DefaultCapture");
  542. lpguidCaptureDeviceIn = &DSDEVID_DefaultCapture;
  543. }
  544. GUID guidTemp;
  545. hr = pfGetDeviceID(lpguidCaptureDeviceIn, &guidTemp);
  546. if (FAILED(hr))
  547. {
  548. DPFX(DPFPREP, DVF_ERRORLEVEL, "GetDeviceID failed: %i", hr);
  549. if (hr == DSERR_NODRIVER)
  550. {
  551. hr = DVERR_INVALIDDEVICE;
  552. }
  553. else
  554. {
  555. hr = DVERR_GENERIC;
  556. }
  557. goto error_cleanup;
  558. }
  559. if (*lpguidCaptureDeviceIn != guidTemp)
  560. {
  561. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Warning: GetDeviceID mapped device GUID");
  562. *lpguidCaptureDeviceOut = guidTemp;
  563. }
  564. else
  565. {
  566. *lpguidCaptureDeviceOut = *lpguidCaptureDeviceIn;
  567. }
  568. }
  569. if (!FreeLibrary(hDSound))
  570. {
  571. lRet = GetLastError();
  572. DPFX(DPFPREP, DVF_ERRORLEVEL, "FreeLibrary failed, code: %i", lRet);
  573. hr = DVERR_GENERIC;
  574. goto error_cleanup;
  575. }
  576. return DV_OK;
  577. error_cleanup:
  578. if (hDSound != NULL)
  579. {
  580. FreeLibrary(hDSound);
  581. }
  582. DPF_EXIT();
  583. return hr;
  584. }
  585. #undef DPF_MODNAME
  586. #define DPF_MODNAME "DV_MapPlaybackDevice"
  587. HRESULT DV_MapPlaybackDevice(const GUID* lpguidPlaybackDeviceIn, GUID* lpguidPlaybackDeviceOut)
  588. {
  589. LONG lRet;
  590. HRESULT hr;
  591. PFGETDEVICEID pfGetDeviceID;
  592. // attempt to map any default guids to real guids...
  593. HINSTANCE hDSound = LoadLibraryA("dsound.dll");
  594. if (hDSound == NULL)
  595. {
  596. lRet = GetLastError();
  597. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to get instance handle to DirectSound dll: %s", "dsound.dll");
  598. DPFX(DPFPREP, DVF_ERRORLEVEL, "LoadLibrary error code: %i", lRet);
  599. hr = DVERR_GENERIC;
  600. goto error_cleanup;
  601. }
  602. // attempt to get a pointer to the GetDeviceId function
  603. pfGetDeviceID = (PFGETDEVICEID)GetProcAddress(hDSound, "GetDeviceID");
  604. if (pfGetDeviceID == NULL)
  605. {
  606. lRet = GetLastError();
  607. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Unable to get a pointer to GetDeviceID function: %s", "GetDeviceID");
  608. DPFX(DPFPREP, DVF_WARNINGLEVEL, "GetProcAddress error code: %i", lRet);
  609. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Assuming that we are running on a Pre-DX7.1 DirectSound", lRet);
  610. // On a pre-DX 7.1 system, we map NULL to GUID_NULL, and that's all, since
  611. // the other "default" guids don't really exist on this system (i.e. if I were
  612. // to pass them to DirectSound, it wouldn't understand.).
  613. if (lpguidPlaybackDeviceIn == NULL ||
  614. *lpguidPlaybackDeviceIn == DSDEVID_DefaultPlayback ||
  615. *lpguidPlaybackDeviceIn == DSDEVID_DefaultVoicePlayback ||
  616. *lpguidPlaybackDeviceIn == GUID_NULL )
  617. {
  618. hr = DV_LegacyMapDefaultGUID( FALSE, lpguidPlaybackDeviceOut );
  619. if( FAILED( hr ) )
  620. {
  621. DNASSERT( FALSE );
  622. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to perform old mapping. Assuming GUID_NULL" );
  623. *lpguidPlaybackDeviceOut = GUID_NULL;
  624. }
  625. }
  626. else
  627. {
  628. *lpguidPlaybackDeviceOut = *lpguidPlaybackDeviceIn;
  629. }
  630. }
  631. else
  632. {
  633. // Use the GetDeviceID function to map the devices.
  634. if (lpguidPlaybackDeviceIn == NULL)
  635. {
  636. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Warning: Mapping null device pointer to DSDEVID_DefaultPlayback");
  637. lpguidPlaybackDeviceIn = &DSDEVID_DefaultPlayback;
  638. }
  639. else if (*lpguidPlaybackDeviceIn == GUID_NULL)
  640. {
  641. // GetDeviceID does not accept GUID_NULL, since it does not know
  642. // if we are asking for a capture or playback device. So we map
  643. // GUID_NULL to the system default playback device here. Then
  644. // GetDeviceID can map it to the real device.
  645. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Warning: Mapping GUID_NULL to DSDEVID_DefaultPlayback");
  646. lpguidPlaybackDeviceIn = &DSDEVID_DefaultPlayback;
  647. }
  648. GUID guidTemp;
  649. hr = pfGetDeviceID(lpguidPlaybackDeviceIn, &guidTemp);
  650. if (FAILED(hr))
  651. {
  652. DPFX(DPFPREP, DVF_ERRORLEVEL, "GetDeviceID failed: %i", hr);
  653. if (hr == DSERR_NODRIVER)
  654. {
  655. hr = DVERR_INVALIDDEVICE;
  656. }
  657. else
  658. {
  659. hr = DVERR_GENERIC;
  660. }
  661. goto error_cleanup;
  662. }
  663. if (*lpguidPlaybackDeviceIn != guidTemp)
  664. {
  665. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Warning: GetDeviceID mapped device GUID");
  666. *lpguidPlaybackDeviceOut = guidTemp;
  667. }
  668. else
  669. {
  670. *lpguidPlaybackDeviceOut = *lpguidPlaybackDeviceIn;
  671. }
  672. }
  673. if (!FreeLibrary(hDSound))
  674. {
  675. lRet = GetLastError();
  676. DPFX(DPFPREP, DVF_ERRORLEVEL, "FreeLibrary failed, code: %i", lRet);
  677. hr = DVERR_GENERIC;
  678. goto error_cleanup;
  679. }
  680. return DV_OK;
  681. error_cleanup:
  682. if (hDSound != NULL)
  683. {
  684. FreeLibrary(hDSound);
  685. }
  686. DPF_EXIT();
  687. return hr;
  688. }