1 /* DirectSound 2 * 3 * Copyright 1998 Marcus Meissner 4 * Copyright 1998 Rob Riggs 5 * Copyright 2000-2002 TransGaming Technologies, Inc. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 * 21 * Most thread locking is complete. There may be a few race 22 * conditions still lurking. 23 * 24 * TODO: 25 * Implement SetCooperativeLevel properly (need to address focus issues) 26 * Implement DirectSound3DBuffers (stubs in place) 27 * Use hardware 3D support if available 28 * Add critical section locking inside Release and AddRef methods 29 * Handle static buffers - put those in hardware, non-static not in hardware 30 * Hardware DuplicateSoundBuffer 31 * Proper volume calculation for 3d buffers 32 * Remove DS_HEL_FRAGS and use mixer fragment length for it 33 */ 34 35 #include "dsound_private.h" 36 37 #include <winreg.h> 38 #include <rpcproxy.h> 39 40 DirectSoundDevice* DSOUND_renderer[MAXWAVEDRIVERS]; 41 GUID DSOUND_renderer_guids[MAXWAVEDRIVERS]; 42 GUID DSOUND_capture_guids[MAXWAVEDRIVERS]; 43 44 HRESULT mmErr(UINT err) 45 { 46 switch(err) { 47 case MMSYSERR_NOERROR: 48 return DS_OK; 49 case MMSYSERR_ALLOCATED: 50 return DSERR_ALLOCATED; 51 case MMSYSERR_ERROR: 52 case MMSYSERR_INVALHANDLE: 53 case WAVERR_STILLPLAYING: 54 return DSERR_GENERIC; /* FIXME */ 55 case MMSYSERR_BADDEVICEID: 56 case MMSYSERR_NODRIVER: 57 return DSERR_NODRIVER; 58 case MMSYSERR_NOMEM: 59 return DSERR_OUTOFMEMORY; 60 case MMSYSERR_INVALPARAM: 61 case WAVERR_BADFORMAT: 62 case WAVERR_UNPREPARED: 63 return DSERR_INVALIDPARAM; 64 case MMSYSERR_NOTSUPPORTED: 65 return DSERR_UNSUPPORTED; 66 default: 67 FIXME("Unknown MMSYS error %d\n",err); 68 return DSERR_GENERIC; 69 } 70 } 71 72 /* All default settings, you most likely don't want to touch these, see wiki on UsefulRegistryKeys */ 73 int ds_emuldriver = 0; 74 int ds_hel_buflen = 32768 * 2; 75 int ds_snd_queue_max = 10; 76 int ds_snd_queue_min = 6; 77 int ds_snd_shadow_maxsize = 2; 78 int ds_hw_accel = DS_HW_ACCEL_FULL; 79 int ds_default_sample_rate = 44100; 80 int ds_default_bits_per_sample = 16; 81 static int ds_default_playback; 82 static int ds_default_capture; 83 static HINSTANCE instance; 84 85 /* 86 * Get a config key from either the app-specific or the default config 87 */ 88 89 static inline DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, 90 char *buffer, DWORD size ) 91 { 92 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0; 93 if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0; 94 return ERROR_FILE_NOT_FOUND; 95 } 96 97 98 /* 99 * Setup the dsound options. 100 */ 101 102 void setup_dsound_options(void) 103 { 104 char buffer[MAX_PATH+16]; 105 HKEY hkey, appkey = 0; 106 DWORD len; 107 108 buffer[MAX_PATH]='\0'; 109 110 /* @@ Wine registry key: HKCU\Software\Wine\DirectSound */ 111 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\DirectSound", &hkey )) hkey = 0; 112 113 len = GetModuleFileNameA( 0, buffer, MAX_PATH ); 114 if (len && len < MAX_PATH) 115 { 116 HKEY tmpkey; 117 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectSound */ 118 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey )) 119 { 120 char *p, *appname = buffer; 121 if ((p = strrchr( appname, '/' ))) appname = p + 1; 122 if ((p = strrchr( appname, '\\' ))) appname = p + 1; 123 strcat( appname, "\\DirectSound" ); 124 TRACE("appname = [%s]\n", appname); 125 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; 126 RegCloseKey( tmpkey ); 127 } 128 } 129 130 /* get options */ 131 132 if (!get_config_key( hkey, appkey, "EmulDriver", buffer, MAX_PATH )) 133 ds_emuldriver = strcmp(buffer, "N"); 134 135 if (!get_config_key( hkey, appkey, "HelBuflen", buffer, MAX_PATH )) 136 ds_hel_buflen = atoi(buffer); 137 138 if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH )) 139 ds_snd_queue_max = atoi(buffer); 140 141 if (!get_config_key( hkey, appkey, "SndQueueMin", buffer, MAX_PATH )) 142 ds_snd_queue_min = atoi(buffer); 143 144 if (!get_config_key( hkey, appkey, "HardwareAcceleration", buffer, MAX_PATH )) { 145 if (strcmp(buffer, "Full") == 0) 146 ds_hw_accel = DS_HW_ACCEL_FULL; 147 else if (strcmp(buffer, "Standard") == 0) 148 ds_hw_accel = DS_HW_ACCEL_STANDARD; 149 else if (strcmp(buffer, "Basic") == 0) 150 ds_hw_accel = DS_HW_ACCEL_BASIC; 151 else if (strcmp(buffer, "Emulation") == 0) 152 ds_hw_accel = DS_HW_ACCEL_EMULATION; 153 } 154 155 if (!get_config_key( hkey, appkey, "DefaultPlayback", buffer, MAX_PATH )) 156 ds_default_playback = atoi(buffer); 157 158 if (!get_config_key( hkey, appkey, "MaxShadowSize", buffer, MAX_PATH )) 159 ds_snd_shadow_maxsize = atoi(buffer); 160 161 if (!get_config_key( hkey, appkey, "DefaultCapture", buffer, MAX_PATH )) 162 ds_default_capture = atoi(buffer); 163 164 if (!get_config_key( hkey, appkey, "DefaultSampleRate", buffer, MAX_PATH )) 165 ds_default_sample_rate = atoi(buffer); 166 167 if (!get_config_key( hkey, appkey, "DefaultBitsPerSample", buffer, MAX_PATH )) 168 ds_default_bits_per_sample = atoi(buffer); 169 170 if (appkey) RegCloseKey( appkey ); 171 if (hkey) RegCloseKey( hkey ); 172 173 TRACE("ds_emuldriver = %d\n", ds_emuldriver); 174 TRACE("ds_hel_buflen = %d\n", ds_hel_buflen); 175 TRACE("ds_snd_queue_max = %d\n", ds_snd_queue_max); 176 TRACE("ds_snd_queue_min = %d\n", ds_snd_queue_min); 177 TRACE("ds_hw_accel = %s\n", 178 ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" : 179 ds_hw_accel==DS_HW_ACCEL_STANDARD ? "Standard" : 180 ds_hw_accel==DS_HW_ACCEL_BASIC ? "Basic" : 181 ds_hw_accel==DS_HW_ACCEL_EMULATION ? "Emulation" : 182 "Unknown"); 183 TRACE("ds_default_playback = %d\n", ds_default_playback); 184 TRACE("ds_default_capture = %d\n", ds_default_playback); 185 TRACE("ds_default_sample_rate = %d\n", ds_default_sample_rate); 186 TRACE("ds_default_bits_per_sample = %d\n", ds_default_bits_per_sample); 187 TRACE("ds_snd_shadow_maxsize = %d\n", ds_snd_shadow_maxsize); 188 } 189 190 static const char * get_device_id(LPCGUID pGuid) 191 { 192 if (IsEqualGUID(&DSDEVID_DefaultPlayback, pGuid)) 193 return "DSDEVID_DefaultPlayback"; 194 else if (IsEqualGUID(&DSDEVID_DefaultVoicePlayback, pGuid)) 195 return "DSDEVID_DefaultVoicePlayback"; 196 else if (IsEqualGUID(&DSDEVID_DefaultCapture, pGuid)) 197 return "DSDEVID_DefaultCapture"; 198 else if (IsEqualGUID(&DSDEVID_DefaultVoiceCapture, pGuid)) 199 return "DSDEVID_DefaultVoiceCapture"; 200 return debugstr_guid(pGuid); 201 } 202 203 /*************************************************************************** 204 * GetDeviceID [DSOUND.9] 205 * 206 * Retrieves unique identifier of default device specified 207 * 208 * PARAMS 209 * pGuidSrc [I] Address of device GUID. 210 * pGuidDest [O] Address to receive unique device GUID. 211 * 212 * RETURNS 213 * Success: DS_OK 214 * Failure: DSERR_INVALIDPARAM 215 * 216 * NOTES 217 * pGuidSrc is a valid device GUID or DSDEVID_DefaultPlayback, 218 * DSDEVID_DefaultCapture, DSDEVID_DefaultVoicePlayback, or 219 * DSDEVID_DefaultVoiceCapture. 220 * Returns pGuidSrc if pGuidSrc is a valid device or the device 221 * GUID for the specified constants. 222 */ 223 HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest) 224 { 225 TRACE("(%s,%p)\n", get_device_id(pGuidSrc),pGuidDest); 226 227 if ( pGuidSrc == NULL) { 228 WARN("invalid parameter: pGuidSrc == NULL\n"); 229 return DSERR_INVALIDPARAM; 230 } 231 232 if ( pGuidDest == NULL ) { 233 WARN("invalid parameter: pGuidDest == NULL\n"); 234 return DSERR_INVALIDPARAM; 235 } 236 237 if ( IsEqualGUID( &DSDEVID_DefaultPlayback, pGuidSrc ) || 238 IsEqualGUID( &DSDEVID_DefaultVoicePlayback, pGuidSrc ) ) { 239 *pGuidDest = DSOUND_renderer_guids[ds_default_playback]; 240 TRACE("returns %s\n", get_device_id(pGuidDest)); 241 return DS_OK; 242 } 243 244 if ( IsEqualGUID( &DSDEVID_DefaultCapture, pGuidSrc ) || 245 IsEqualGUID( &DSDEVID_DefaultVoiceCapture, pGuidSrc ) ) { 246 *pGuidDest = DSOUND_capture_guids[ds_default_capture]; 247 TRACE("returns %s\n", get_device_id(pGuidDest)); 248 return DS_OK; 249 } 250 251 *pGuidDest = *pGuidSrc; 252 TRACE("returns %s\n", get_device_id(pGuidDest)); 253 254 return DS_OK; 255 } 256 257 struct morecontext 258 { 259 LPDSENUMCALLBACKA callA; 260 LPVOID data; 261 }; 262 263 static BOOL CALLBACK a_to_w_callback(LPGUID guid, LPCWSTR descW, LPCWSTR modW, LPVOID data) 264 { 265 struct morecontext *context = data; 266 char descA[MAXPNAMELEN], modA[MAXPNAMELEN]; 267 268 WideCharToMultiByte(CP_ACP, 0, descW, -1, descA, sizeof(descA), NULL, NULL); 269 WideCharToMultiByte(CP_ACP, 0, modW, -1, modA, sizeof(modA), NULL, NULL); 270 271 return context->callA(guid, descA, modA, context->data); 272 } 273 274 /*************************************************************************** 275 * DirectSoundEnumerateA [DSOUND.2] 276 * 277 * Enumerate all DirectSound drivers installed in the system 278 * 279 * PARAMS 280 * lpDSEnumCallback [I] Address of callback function. 281 * lpContext [I] Address of user defined context passed to callback function. 282 * 283 * RETURNS 284 * Success: DS_OK 285 * Failure: DSERR_INVALIDPARAM 286 */ 287 HRESULT WINAPI DirectSoundEnumerateA( 288 LPDSENUMCALLBACKA lpDSEnumCallback, 289 LPVOID lpContext) 290 { 291 struct morecontext context; 292 293 if (lpDSEnumCallback == NULL) { 294 WARN("invalid parameter: lpDSEnumCallback == NULL\n"); 295 return DSERR_INVALIDPARAM; 296 } 297 298 context.callA = lpDSEnumCallback; 299 context.data = lpContext; 300 301 return DirectSoundEnumerateW(a_to_w_callback, &context); 302 } 303 304 /*************************************************************************** 305 * DirectSoundEnumerateW [DSOUND.3] 306 * 307 * Enumerate all DirectSound drivers installed in the system 308 * 309 * PARAMS 310 * lpDSEnumCallback [I] Address of callback function. 311 * lpContext [I] Address of user defined context passed to callback function. 312 * 313 * RETURNS 314 * Success: DS_OK 315 * Failure: DSERR_INVALIDPARAM 316 */ 317 HRESULT WINAPI DirectSoundEnumerateW( 318 LPDSENUMCALLBACKW lpDSEnumCallback, 319 LPVOID lpContext ) 320 { 321 unsigned devs, wod; 322 WAVEOUTCAPSW capsW; 323 GUID guid; 324 int err; 325 326 TRACE("lpDSEnumCallback = %p, lpContext = %p\n", 327 lpDSEnumCallback, lpContext); 328 329 if (lpDSEnumCallback == NULL) { 330 WARN("invalid parameter: lpDSEnumCallback == NULL\n"); 331 return DSERR_INVALIDPARAM; 332 } 333 334 setup_dsound_options(); 335 336 devs = waveOutGetNumDevs(); 337 if (devs > 0) { 338 if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) { 339 for (wod = 0; wod < devs; ++wod) { 340 if (IsEqualGUID( &guid, &DSOUND_renderer_guids[wod] ) ) { 341 err = mmErr(waveOutGetDevCapsW(wod, &capsW, sizeof(WAVEOUTCAPSW))); 342 if (err == DS_OK) { 343 TRACE("calling lpDSEnumCallback(NULL,\"%ls\",\"%ls\",%p)\n", 344 capsW.szPname,L"Primary Sound Driver",lpContext); 345 if (lpDSEnumCallback(NULL, capsW.szPname, L"Primary Sound Driver", lpContext) == FALSE) 346 return DS_OK; 347 } 348 } 349 } 350 } 351 } 352 353 for (wod = 0; wod < devs; ++wod) { 354 err = mmErr(waveOutGetDevCapsW(wod, &capsW, sizeof(WAVEOUTCAPSW))); 355 if (err == DS_OK) { 356 TRACE("calling lpDSEnumCallback(%s,\"%ls\",\"%ls\",%p)\n", 357 debugstr_guid(&DSOUND_renderer_guids[wod]),capsW.szPname,L"Primary Sound Driver",lpContext); 358 if (lpDSEnumCallback(&DSOUND_renderer_guids[wod], capsW.szPname, L"Primary Sound Driver", lpContext) == FALSE) 359 return DS_OK; 360 } 361 } 362 return DS_OK; 363 } 364 365 /*************************************************************************** 366 * DirectSoundCaptureEnumerateA [DSOUND.7] 367 * 368 * Enumerate all DirectSound drivers installed in the system. 369 * 370 * PARAMS 371 * lpDSEnumCallback [I] Address of callback function. 372 * lpContext [I] Address of user defined context passed to callback function. 373 * 374 * RETURNS 375 * Success: DS_OK 376 * Failure: DSERR_INVALIDPARAM 377 */ 378 HRESULT WINAPI DirectSoundCaptureEnumerateA( 379 LPDSENUMCALLBACKA lpDSEnumCallback, 380 LPVOID lpContext) 381 { 382 struct morecontext context; 383 384 if (lpDSEnumCallback == NULL) { 385 WARN("invalid parameter: lpDSEnumCallback == NULL\n"); 386 return DSERR_INVALIDPARAM; 387 } 388 389 context.callA = lpDSEnumCallback; 390 context.data = lpContext; 391 392 return DirectSoundCaptureEnumerateW(a_to_w_callback, &context); 393 } 394 395 /*************************************************************************** 396 * DirectSoundCaptureEnumerateW [DSOUND.8] 397 * 398 * Enumerate all DirectSound drivers installed in the system. 399 * 400 * PARAMS 401 * lpDSEnumCallback [I] Address of callback function. 402 * lpContext [I] Address of user defined context passed to callback function. 403 * 404 * RETURNS 405 * Success: DS_OK 406 * Failure: DSERR_INVALIDPARAM 407 */ 408 HRESULT WINAPI 409 DirectSoundCaptureEnumerateW( 410 LPDSENUMCALLBACKW lpDSEnumCallback, 411 LPVOID lpContext) 412 { 413 unsigned devs, wid; 414 WAVEINCAPSW capsW; 415 GUID guid; 416 int err; 417 418 TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext ); 419 420 if (lpDSEnumCallback == NULL) { 421 WARN("invalid parameter: lpDSEnumCallback == NULL\n"); 422 return DSERR_INVALIDPARAM; 423 } 424 425 setup_dsound_options(); 426 427 devs = waveInGetNumDevs(); 428 if (devs > 0) { 429 if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) { 430 for (wid = 0; wid < devs; ++wid) { 431 if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) { 432 err = mmErr(waveInGetDevCapsW(wid, &capsW, sizeof(WAVEINCAPSW))); 433 if (err == DS_OK) { 434 TRACE("calling lpDSEnumCallback(NULL,\"%ls\",\"%ls\",%p)\n", 435 capsW.szPname,L"Primary Sound Capture Driver",lpContext); 436 if (lpDSEnumCallback(NULL, capsW.szPname, L"Primary Sound Capture Driver", lpContext) == FALSE) 437 return DS_OK; 438 } 439 } 440 } 441 } 442 } 443 444 for (wid = 0; wid < devs; ++wid) { 445 err = mmErr(waveInGetDevCapsW(wid, &capsW, sizeof(WAVEINCAPSW))); 446 if (err == DS_OK) { 447 TRACE("calling lpDSEnumCallback(%s,\"%ls\",\"%ls\",%p)\n", 448 debugstr_guid(&DSOUND_capture_guids[wid]),capsW.szPname,L"Primary Sound Capture Driver",lpContext); 449 if (lpDSEnumCallback(&DSOUND_capture_guids[wid], capsW.szPname, L"Primary Sound Capture Driver", lpContext) == FALSE) 450 return DS_OK; 451 } 452 } 453 454 return DS_OK; 455 } 456 457 /******************************************************************************* 458 * DirectSound ClassFactory 459 */ 460 461 typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj); 462 463 typedef struct { 464 IClassFactory IClassFactory_iface; 465 REFCLSID rclsid; 466 FnCreateInstance pfnCreateInstance; 467 } IClassFactoryImpl; 468 469 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface) 470 { 471 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface); 472 } 473 474 static HRESULT WINAPI 475 DSCF_QueryInterface(LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj) 476 { 477 IClassFactoryImpl *This = impl_from_IClassFactory(iface); 478 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj); 479 if (ppobj == NULL) 480 return E_POINTER; 481 if (IsEqualIID(riid, &IID_IUnknown) || 482 IsEqualIID(riid, &IID_IClassFactory)) 483 { 484 *ppobj = iface; 485 IUnknown_AddRef(iface); 486 return S_OK; 487 } 488 *ppobj = NULL; 489 return E_NOINTERFACE; 490 } 491 492 static ULONG WINAPI DSCF_AddRef(LPCLASSFACTORY iface) 493 { 494 return 2; 495 } 496 497 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) 498 { 499 /* static class, won't be freed */ 500 return 1; 501 } 502 503 static HRESULT WINAPI DSCF_CreateInstance( 504 LPCLASSFACTORY iface, 505 LPUNKNOWN pOuter, 506 REFIID riid, 507 LPVOID *ppobj) 508 { 509 IClassFactoryImpl *This = impl_from_IClassFactory(iface); 510 TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj); 511 512 if (pOuter) 513 return CLASS_E_NOAGGREGATION; 514 515 if (ppobj == NULL) { 516 WARN("invalid parameter\n"); 517 return DSERR_INVALIDPARAM; 518 } 519 *ppobj = NULL; 520 return This->pfnCreateInstance(riid, ppobj); 521 } 522 523 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) 524 { 525 IClassFactoryImpl *This = impl_from_IClassFactory(iface); 526 FIXME("(%p, %d) stub!\n", This, dolock); 527 return S_OK; 528 } 529 530 static const IClassFactoryVtbl DSCF_Vtbl = { 531 DSCF_QueryInterface, 532 DSCF_AddRef, 533 DSCF_Release, 534 DSCF_CreateInstance, 535 DSCF_LockServer 536 }; 537 538 static IClassFactoryImpl DSOUND_CF[] = { 539 { { &DSCF_Vtbl }, &CLSID_DirectSound, (FnCreateInstance)DSOUND_Create }, 540 { { &DSCF_Vtbl }, &CLSID_DirectSound8, (FnCreateInstance)DSOUND_Create8 }, 541 { { &DSCF_Vtbl }, &CLSID_DirectSoundCapture, (FnCreateInstance)DSOUND_CaptureCreate }, 542 { { &DSCF_Vtbl }, &CLSID_DirectSoundCapture8, (FnCreateInstance)DSOUND_CaptureCreate8 }, 543 { { &DSCF_Vtbl }, &CLSID_DirectSoundFullDuplex, (FnCreateInstance)DSOUND_FullDuplexCreate }, 544 { { &DSCF_Vtbl }, &CLSID_DirectSoundPrivate, (FnCreateInstance)IKsPrivatePropertySetImpl_Create }, 545 { { NULL }, NULL, NULL } 546 }; 547 548 /******************************************************************************* 549 * DllGetClassObject [DSOUND.@] 550 * Retrieves class object from a DLL object 551 * 552 * NOTES 553 * Docs say returns STDAPI 554 * 555 * PARAMS 556 * rclsid [I] CLSID for the class object 557 * riid [I] Reference to identifier of interface for class object 558 * ppv [O] Address of variable to receive interface pointer for riid 559 * 560 * RETURNS 561 * Success: S_OK 562 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG, 563 * E_UNEXPECTED 564 */ 565 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 566 { 567 int i = 0; 568 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); 569 570 if (ppv == NULL) { 571 WARN("invalid parameter\n"); 572 return E_INVALIDARG; 573 } 574 575 *ppv = NULL; 576 577 if (!IsEqualIID(riid, &IID_IClassFactory) && 578 !IsEqualIID(riid, &IID_IUnknown)) { 579 WARN("no interface for %s\n", debugstr_guid(riid)); 580 return E_NOINTERFACE; 581 } 582 583 while (NULL != DSOUND_CF[i].rclsid) { 584 if (IsEqualGUID(rclsid, DSOUND_CF[i].rclsid)) { 585 DSCF_AddRef(&DSOUND_CF[i].IClassFactory_iface); 586 *ppv = &DSOUND_CF[i]; 587 return S_OK; 588 } 589 i++; 590 } 591 592 WARN("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid), 593 debugstr_guid(riid), ppv); 594 return CLASS_E_CLASSNOTAVAILABLE; 595 } 596 597 598 /******************************************************************************* 599 * DllCanUnloadNow [DSOUND.4] 600 * Determines whether the DLL is in use. 601 * 602 * RETURNS 603 * Can unload now: S_OK 604 * Cannot unload now (the DLL is still active): S_FALSE 605 */ 606 HRESULT WINAPI DllCanUnloadNow(void) 607 { 608 return S_FALSE; 609 } 610 611 #define INIT_GUID(guid, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 612 guid.Data1 = l; guid.Data2 = w1; guid.Data3 = w2; \ 613 guid.Data4[0] = b1; guid.Data4[1] = b2; guid.Data4[2] = b3; \ 614 guid.Data4[3] = b4; guid.Data4[4] = b5; guid.Data4[5] = b6; \ 615 guid.Data4[6] = b7; guid.Data4[7] = b8; 616 617 /*********************************************************************** 618 * DllMain (DSOUND.init) 619 */ 620 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved) 621 { 622 int i; 623 TRACE("(%p %d %p)\n", hInstDLL, fdwReason, lpvReserved); 624 625 switch (fdwReason) { 626 case DLL_PROCESS_ATTACH: 627 TRACE("DLL_PROCESS_ATTACH\n"); 628 for (i = 0; i < MAXWAVEDRIVERS; i++) { 629 DSOUND_renderer[i] = NULL; 630 DSOUND_capture[i] = NULL; 631 INIT_GUID(DSOUND_renderer_guids[i], 0xbd6dd71a, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i); 632 INIT_GUID(DSOUND_capture_guids[i], 0xbd6dd71b, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i); 633 } 634 instance = hInstDLL; 635 DisableThreadLibraryCalls(hInstDLL); 636 /* Increase refcount on dsound by 1 */ 637 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)hInstDLL, &hInstDLL); 638 break; 639 case DLL_PROCESS_DETACH: 640 TRACE("DLL_PROCESS_DETACH\n"); 641 break; 642 default: 643 TRACE("UNKNOWN REASON\n"); 644 break; 645 } 646 return TRUE; 647 } 648 649 /*********************************************************************** 650 * DllRegisterServer (DSOUND.@) 651 */ 652 HRESULT WINAPI DllRegisterServer(void) 653 { 654 return __wine_register_resources( instance ); 655 } 656 657 /*********************************************************************** 658 * DllUnregisterServer (DSOUND.@) 659 */ 660 HRESULT WINAPI DllUnregisterServer(void) 661 { 662 return __wine_unregister_resources( instance ); 663 } 664