Use the correct type instead of a macro alias
[dsound-openal.git] / dsound_main.c
blob20686224c20fc3a32abf9e13d6bb8f85459d5651
1 /* DirectSound
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
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.
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.
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
21 * Most thread locking is complete. There may be a few race
22 * conditions still lurking.
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
35 #define CONST_VTABLE
36 #include <stdarg.h>
37 #include <string.h>
39 #include <windows.h>
40 #include <dsound.h>
41 #include <mmsystem.h>
42 #include <mmdeviceapi.h>
43 #include <devpropdef.h>
45 #include "dsound_private.h"
47 #ifndef DECLSPEC_EXPORT
48 #ifdef _WIN32
49 #define DECLSPEC_EXPORT __declspec(dllexport)
50 #else
51 #define DECLSPEC_EXPORT
52 #endif
53 #endif
55 DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e,0xdf1c,0x4efd,0x80,0x20,0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
56 DEFINE_GUID(CLSID_DirectSoundPrivate,0x11ab3ec0,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
58 int LogLevel = 1;
59 FILE *LogFile;
62 const WCHAR wine_vxd_drv[] = L"winemm.vxd";
64 const IID DSPROPSETID_EAX_ReverbProperties = {
65 0x4a4e6fc1, 0xc341, 0x11d1, { 0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 }
67 const IID DSPROPSETID_EAXBUFFER_ReverbProperties = {
68 0x4a4e6fc0, 0xc341, 0x11d1, { 0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 }
71 const IID DSPROPSETID_EAX20_ListenerProperties = {
72 0x0306a6a8, 0xb224, 0x11d2, { 0x99, 0xe5, 0x00, 0x00, 0xe8, 0xd8, 0xc7, 0x22 }
74 const IID DSPROPSETID_EAX20_BufferProperties = {
75 0x0306a6a7, 0xb224, 0x11d2, { 0x99, 0xe5, 0x00, 0x00, 0xe8, 0xd8, 0xc7, 0x22 }
78 const EAXLISTENERPROPERTIES EnvironmentDefaults[EAX_ENVIRONMENT_COUNT] =
80 REVERB_PRESET_GENERIC,
81 REVERB_PRESET_PADDEDCELL,
82 REVERB_PRESET_ROOM,
83 REVERB_PRESET_BATHROOM,
84 REVERB_PRESET_LIVINGROOM,
85 REVERB_PRESET_STONEROOM,
86 REVERB_PRESET_AUDITORIUM,
87 REVERB_PRESET_CONCERTHALL,
88 REVERB_PRESET_CAVE,
89 REVERB_PRESET_ARENA,
90 REVERB_PRESET_HANGAR,
91 REVERB_PRESET_CARPETEDHALLWAY,
92 REVERB_PRESET_HALLWAY,
93 REVERB_PRESET_STONECORRIDOR,
94 REVERB_PRESET_ALLEY,
95 REVERB_PRESET_FOREST,
96 REVERB_PRESET_CITY,
97 REVERB_PRESET_MOUNTAINS,
98 REVERB_PRESET_QUARRY,
99 REVERB_PRESET_PLAIN,
100 REVERB_PRESET_PARKINGLOT,
101 REVERB_PRESET_SEWERPIPE,
102 REVERB_PRESET_UNDERWATER,
103 REVERB_PRESET_DRUGGED,
104 REVERB_PRESET_DIZZY,
105 REVERB_PRESET_PSYCHOTIC
108 static CRITICAL_SECTION_DEBUG openal_crst_debug =
110 0, 0, &openal_crst,
111 { &openal_crst_debug.ProcessLocksList,
112 &openal_crst_debug.ProcessLocksList },
113 0, 0, { (DWORD_PTR)(__FILE__ ": openal_crst_debug") }
115 CRITICAL_SECTION openal_crst = { &openal_crst_debug, -1, 0, 0, 0, 0 };
117 int openal_loaded = 0;
118 static HANDLE openal_handle = NULL;
119 LPALCCREATECONTEXT palcCreateContext = NULL;
120 LPALCMAKECONTEXTCURRENT palcMakeContextCurrent = NULL;
121 LPALCPROCESSCONTEXT palcProcessContext = NULL;
122 LPALCSUSPENDCONTEXT palcSuspendContext = NULL;
123 LPALCDESTROYCONTEXT palcDestroyContext = NULL;
124 LPALCGETCURRENTCONTEXT palcGetCurrentContext = NULL;
125 LPALCGETCONTEXTSDEVICE palcGetContextsDevice = NULL;
126 LPALCOPENDEVICE palcOpenDevice = NULL;
127 LPALCCLOSEDEVICE palcCloseDevice = NULL;
128 LPALCGETERROR palcGetError = NULL;
129 LPALCISEXTENSIONPRESENT palcIsExtensionPresent = NULL;
130 LPALCGETPROCADDRESS palcGetProcAddress = NULL;
131 LPALCGETENUMVALUE palcGetEnumValue = NULL;
132 LPALCGETSTRING palcGetString = NULL;
133 LPALCGETINTEGERV palcGetIntegerv = NULL;
134 LPALCCAPTUREOPENDEVICE palcCaptureOpenDevice = NULL;
135 LPALCCAPTURECLOSEDEVICE palcCaptureCloseDevice = NULL;
136 LPALCCAPTURESTART palcCaptureStart = NULL;
137 LPALCCAPTURESTOP palcCaptureStop = NULL;
138 LPALCCAPTURESAMPLES palcCaptureSamples = NULL;
139 LPALENABLE palEnable = NULL;
140 LPALDISABLE palDisable = NULL;
141 LPALISENABLED palIsEnabled = NULL;
142 LPALGETSTRING palGetString = NULL;
143 LPALGETBOOLEANV palGetBooleanv = NULL;
144 LPALGETINTEGERV palGetIntegerv = NULL;
145 LPALGETFLOATV palGetFloatv = NULL;
146 LPALGETDOUBLEV palGetDoublev = NULL;
147 LPALGETBOOLEAN palGetBoolean = NULL;
148 LPALGETINTEGER palGetInteger = NULL;
149 LPALGETFLOAT palGetFloat = NULL;
150 LPALGETDOUBLE palGetDouble = NULL;
151 LPALGETERROR palGetError = NULL;
152 LPALISEXTENSIONPRESENT palIsExtensionPresent = NULL;
153 LPALGETPROCADDRESS palGetProcAddress = NULL;
154 LPALGETENUMVALUE palGetEnumValue = NULL;
155 LPALLISTENERF palListenerf = NULL;
156 LPALLISTENER3F palListener3f = NULL;
157 LPALLISTENERFV palListenerfv = NULL;
158 LPALLISTENERI palListeneri = NULL;
159 LPALLISTENER3I palListener3i = NULL;
160 LPALLISTENERIV palListeneriv = NULL;
161 LPALGETLISTENERF palGetListenerf = NULL;
162 LPALGETLISTENER3F palGetListener3f = NULL;
163 LPALGETLISTENERFV palGetListenerfv = NULL;
164 LPALGETLISTENERI palGetListeneri = NULL;
165 LPALGETLISTENER3I palGetListener3i = NULL;
166 LPALGETLISTENERIV palGetListeneriv = NULL;
167 LPALGENSOURCES palGenSources = NULL;
168 LPALDELETESOURCES palDeleteSources = NULL;
169 LPALISSOURCE palIsSource = NULL;
170 LPALSOURCEF palSourcef = NULL;
171 LPALSOURCE3F palSource3f = NULL;
172 LPALSOURCEFV palSourcefv = NULL;
173 LPALSOURCEI palSourcei = NULL;
174 LPALSOURCE3I palSource3i = NULL;
175 LPALSOURCEIV palSourceiv = NULL;
176 LPALGETSOURCEF palGetSourcef = NULL;
177 LPALGETSOURCE3F palGetSource3f = NULL;
178 LPALGETSOURCEFV palGetSourcefv = NULL;
179 LPALGETSOURCEI palGetSourcei = NULL;
180 LPALGETSOURCE3I palGetSource3i = NULL;
181 LPALGETSOURCEIV palGetSourceiv = NULL;
182 LPALSOURCEPLAYV palSourcePlayv = NULL;
183 LPALSOURCESTOPV palSourceStopv = NULL;
184 LPALSOURCEREWINDV palSourceRewindv = NULL;
185 LPALSOURCEPAUSEV palSourcePausev = NULL;
186 LPALSOURCEPLAY palSourcePlay = NULL;
187 LPALSOURCESTOP palSourceStop = NULL;
188 LPALSOURCEREWIND palSourceRewind = NULL;
189 LPALSOURCEPAUSE palSourcePause = NULL;
190 LPALSOURCEQUEUEBUFFERS palSourceQueueBuffers = NULL;
191 LPALSOURCEUNQUEUEBUFFERS palSourceUnqueueBuffers = NULL;
192 LPALGENBUFFERS palGenBuffers = NULL;
193 LPALDELETEBUFFERS palDeleteBuffers = NULL;
194 LPALISBUFFER palIsBuffer = NULL;
195 LPALBUFFERF palBufferf = NULL;
196 LPALBUFFER3F palBuffer3f = NULL;
197 LPALBUFFERFV palBufferfv = NULL;
198 LPALBUFFERI palBufferi = NULL;
199 LPALBUFFER3I palBuffer3i = NULL;
200 LPALBUFFERIV palBufferiv = NULL;
201 LPALGETBUFFERF palGetBufferf = NULL;
202 LPALGETBUFFER3F palGetBuffer3f = NULL;
203 LPALGETBUFFERFV palGetBufferfv = NULL;
204 LPALGETBUFFERI palGetBufferi = NULL;
205 LPALGETBUFFER3I palGetBuffer3i = NULL;
206 LPALGETBUFFERIV palGetBufferiv = NULL;
207 LPALBUFFERDATA palBufferData = NULL;
208 LPALDOPPLERFACTOR palDopplerFactor = NULL;
209 LPALDOPPLERVELOCITY palDopplerVelocity = NULL;
210 LPALDISTANCEMODEL palDistanceModel = NULL;
211 LPALSPEEDOFSOUND palSpeedOfSound = NULL;
213 LPALGENFILTERS palGenFilters = NULL;
214 LPALDELETEFILTERS palDeleteFilters = NULL;
215 LPALFILTERI palFilteri = NULL;
216 LPALFILTERF palFilterf = NULL;
217 LPALGENEFFECTS palGenEffects = NULL;
218 LPALDELETEEFFECTS palDeleteEffects = NULL;
219 LPALEFFECTI palEffecti = NULL;
220 LPALEFFECTF palEffectf = NULL;
221 LPALGENAUXILIARYEFFECTSLOTS palGenAuxiliaryEffectSlots = NULL;
222 LPALDELETEAUXILIARYEFFECTSLOTS palDeleteAuxiliaryEffectSlots = NULL;
223 LPALAUXILIARYEFFECTSLOTI palAuxiliaryEffectSloti = NULL;
224 LPALDEFERUPDATESSOFT palDeferUpdatesSOFT = NULL;
225 LPALPROCESSUPDATESSOFT palProcessUpdatesSOFT = NULL;
226 LPALBUFFERSTORAGESOFT palBufferStorageSOFT = NULL;
227 LPALMAPBUFFERSOFT palMapBufferSOFT = NULL;
228 LPALUNMAPBUFFERSOFT palUnmapBufferSOFT = NULL;
229 LPALFLUSHMAPPEDBUFFERSOFT palFlushMappedBufferSOFT = NULL;
231 LPALCMAKECONTEXTCURRENT set_context;
232 LPALCGETCURRENTCONTEXT get_context;
233 BOOL local_contexts;
236 static void AL_APIENTRY wrap_DeferUpdates(void)
237 { alcSuspendContext(alcGetCurrentContext()); }
238 static void AL_APIENTRY wrap_ProcessUpdates(void)
239 { alcProcessContext(alcGetCurrentContext()); }
241 static void EnterALSectionTLS(ALCcontext *ctx);
242 static void LeaveALSectionTLS(void);
243 static void EnterALSectionGlob(ALCcontext *ctx);
244 static void LeaveALSectionGlob(void);
246 DWORD TlsThreadPtr;
247 void (*EnterALSection)(ALCcontext *ctx) = EnterALSectionGlob;
248 void (*LeaveALSection)(void) = LeaveALSectionGlob;
251 static BOOL load_libopenal(void)
253 const char libname[] = "dsoal-aldrv.dll";
254 BOOL failed = FALSE;
255 const char *str;
257 str = getenv("DSOAL_LOGLEVEL");
258 if(str && *str)
259 LogLevel = atoi(str);
261 openal_handle = LoadLibraryA(libname);
262 if(!openal_handle)
264 ERR("Couldn't load %s: %lu\n", libname, GetLastError());
265 return FALSE;
268 #define LOAD_FUNCPTR(f) do { \
269 if((*((void**)&p##f) = GetProcAddress(openal_handle, #f)) == NULL) \
271 ERR("Couldn't lookup %s in %s\n", #f, libname); \
272 failed = TRUE; \
274 } while(0)
276 LOAD_FUNCPTR(alcCreateContext);
277 LOAD_FUNCPTR(alcMakeContextCurrent);
278 LOAD_FUNCPTR(alcProcessContext);
279 LOAD_FUNCPTR(alcSuspendContext);
280 LOAD_FUNCPTR(alcDestroyContext);
281 LOAD_FUNCPTR(alcGetCurrentContext);
282 LOAD_FUNCPTR(alcGetContextsDevice);
283 LOAD_FUNCPTR(alcOpenDevice);
284 LOAD_FUNCPTR(alcCloseDevice);
285 LOAD_FUNCPTR(alcGetError);
286 LOAD_FUNCPTR(alcIsExtensionPresent);
287 LOAD_FUNCPTR(alcGetProcAddress);
288 LOAD_FUNCPTR(alcGetEnumValue);
289 LOAD_FUNCPTR(alcGetString);
290 LOAD_FUNCPTR(alcGetIntegerv);
291 LOAD_FUNCPTR(alcCaptureOpenDevice);
292 LOAD_FUNCPTR(alcCaptureCloseDevice);
293 LOAD_FUNCPTR(alcCaptureStart);
294 LOAD_FUNCPTR(alcCaptureStop);
295 LOAD_FUNCPTR(alcCaptureSamples);
296 LOAD_FUNCPTR(alEnable);
297 LOAD_FUNCPTR(alDisable);
298 LOAD_FUNCPTR(alIsEnabled);
299 LOAD_FUNCPTR(alGetString);
300 LOAD_FUNCPTR(alGetBooleanv);
301 LOAD_FUNCPTR(alGetIntegerv);
302 LOAD_FUNCPTR(alGetFloatv);
303 LOAD_FUNCPTR(alGetDoublev);
304 LOAD_FUNCPTR(alGetBoolean);
305 LOAD_FUNCPTR(alGetInteger);
306 LOAD_FUNCPTR(alGetFloat);
307 LOAD_FUNCPTR(alGetDouble);
308 LOAD_FUNCPTR(alGetError);
309 LOAD_FUNCPTR(alIsExtensionPresent);
310 LOAD_FUNCPTR(alGetProcAddress);
311 LOAD_FUNCPTR(alGetEnumValue);
312 LOAD_FUNCPTR(alListenerf);
313 LOAD_FUNCPTR(alListener3f);
314 LOAD_FUNCPTR(alListenerfv);
315 LOAD_FUNCPTR(alListeneri);
316 LOAD_FUNCPTR(alListener3i);
317 LOAD_FUNCPTR(alListeneriv);
318 LOAD_FUNCPTR(alGetListenerf);
319 LOAD_FUNCPTR(alGetListener3f);
320 LOAD_FUNCPTR(alGetListenerfv);
321 LOAD_FUNCPTR(alGetListeneri);
322 LOAD_FUNCPTR(alGetListener3i);
323 LOAD_FUNCPTR(alGetListeneriv);
324 LOAD_FUNCPTR(alGenSources);
325 LOAD_FUNCPTR(alDeleteSources);
326 LOAD_FUNCPTR(alIsSource);
327 LOAD_FUNCPTR(alSourcef);
328 LOAD_FUNCPTR(alSource3f);
329 LOAD_FUNCPTR(alSourcefv);
330 LOAD_FUNCPTR(alSourcei);
331 LOAD_FUNCPTR(alSource3i);
332 LOAD_FUNCPTR(alSourceiv);
333 LOAD_FUNCPTR(alGetSourcef);
334 LOAD_FUNCPTR(alGetSource3f);
335 LOAD_FUNCPTR(alGetSourcefv);
336 LOAD_FUNCPTR(alGetSourcei);
337 LOAD_FUNCPTR(alGetSource3i);
338 LOAD_FUNCPTR(alGetSourceiv);
339 LOAD_FUNCPTR(alSourcePlayv);
340 LOAD_FUNCPTR(alSourceStopv);
341 LOAD_FUNCPTR(alSourceRewindv);
342 LOAD_FUNCPTR(alSourcePausev);
343 LOAD_FUNCPTR(alSourcePlay);
344 LOAD_FUNCPTR(alSourceStop);
345 LOAD_FUNCPTR(alSourceRewind);
346 LOAD_FUNCPTR(alSourcePause);
347 LOAD_FUNCPTR(alSourceQueueBuffers);
348 LOAD_FUNCPTR(alSourceUnqueueBuffers);
349 LOAD_FUNCPTR(alGenBuffers);
350 LOAD_FUNCPTR(alDeleteBuffers);
351 LOAD_FUNCPTR(alIsBuffer);
352 LOAD_FUNCPTR(alBufferf);
353 LOAD_FUNCPTR(alBuffer3f);
354 LOAD_FUNCPTR(alBufferfv);
355 LOAD_FUNCPTR(alBufferi);
356 LOAD_FUNCPTR(alBuffer3i);
357 LOAD_FUNCPTR(alBufferiv);
358 LOAD_FUNCPTR(alGetBufferf);
359 LOAD_FUNCPTR(alGetBuffer3f);
360 LOAD_FUNCPTR(alGetBufferfv);
361 LOAD_FUNCPTR(alGetBufferi);
362 LOAD_FUNCPTR(alGetBuffer3i);
363 LOAD_FUNCPTR(alGetBufferiv);
364 LOAD_FUNCPTR(alBufferData);
365 LOAD_FUNCPTR(alDopplerFactor);
366 LOAD_FUNCPTR(alDopplerVelocity);
367 LOAD_FUNCPTR(alDistanceModel);
368 LOAD_FUNCPTR(alSpeedOfSound);
369 #undef LOAD_FUNCPTR
370 if (failed)
372 WARN("Unloading %s\n", libname);
373 if (openal_handle != NULL)
374 FreeLibrary(openal_handle);
375 openal_handle = NULL;
376 return FALSE;
379 openal_loaded = 1;
380 TRACE("Loaded %s\n", libname);
382 #define LOAD_FUNCPTR(f) *((void**)&p##f) = alcGetProcAddress(NULL, #f)
383 LOAD_FUNCPTR(alGenFilters);
384 LOAD_FUNCPTR(alDeleteFilters);
385 LOAD_FUNCPTR(alFilteri);
386 LOAD_FUNCPTR(alFilterf);
387 LOAD_FUNCPTR(alGenEffects);
388 LOAD_FUNCPTR(alDeleteEffects);
389 LOAD_FUNCPTR(alEffecti);
390 LOAD_FUNCPTR(alEffectf);
391 LOAD_FUNCPTR(alGenAuxiliaryEffectSlots);
392 LOAD_FUNCPTR(alDeleteAuxiliaryEffectSlots);
393 LOAD_FUNCPTR(alAuxiliaryEffectSloti);
394 LOAD_FUNCPTR(alDeferUpdatesSOFT);
395 LOAD_FUNCPTR(alProcessUpdatesSOFT);
396 LOAD_FUNCPTR(alBufferStorageSOFT);
397 LOAD_FUNCPTR(alMapBufferSOFT);
398 LOAD_FUNCPTR(alUnmapBufferSOFT);
399 LOAD_FUNCPTR(alFlushMappedBufferSOFT);
400 #undef LOAD_FUNCPTR
401 if(!palDeferUpdatesSOFT || !palProcessUpdatesSOFT)
403 palDeferUpdatesSOFT = wrap_DeferUpdates;
404 palProcessUpdatesSOFT = wrap_ProcessUpdates;
407 local_contexts = alcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context");
408 if(local_contexts)
410 TRACE("Found ALC_EXT_thread_local_context\n");
412 set_context = alcGetProcAddress(NULL, "alcSetThreadContext");
413 get_context = alcGetProcAddress(NULL, "alcGetThreadContext");
414 if(!set_context || !get_context)
416 ERR("TLS advertised but functions not found, disabling thread local contexts\n");
417 local_contexts = 0;
420 if(!local_contexts)
422 set_context = alcMakeContextCurrent;
423 get_context = alcGetCurrentContext;
425 else
427 EnterALSection = EnterALSectionTLS;
428 LeaveALSection = LeaveALSectionTLS;
431 return TRUE;
435 static void EnterALSectionTLS(ALCcontext *ctx)
437 if(LIKELY(ctx == TlsGetValue(TlsThreadPtr)))
438 return;
440 if(LIKELY(set_context(ctx) != ALC_FALSE))
441 TlsSetValue(TlsThreadPtr, ctx);
442 else
444 ERR("Couldn't set current context!!\n");
445 checkALCError(alcGetContextsDevice(ctx));
448 static void LeaveALSectionTLS(void)
452 static void EnterALSectionGlob(ALCcontext *ctx)
454 EnterCriticalSection(&openal_crst);
455 if(UNLIKELY(alcMakeContextCurrent(ctx) == ALC_FALSE))
457 ERR("Couldn't set current context!!\n");
458 checkALCError(alcGetContextsDevice(ctx));
461 static void LeaveALSectionGlob(void)
463 LeaveCriticalSection(&openal_crst);
467 static const char *get_device_id(LPCGUID pGuid)
469 if(IsEqualGUID(&DSDEVID_DefaultPlayback, pGuid))
470 return "DSDEVID_DefaultPlayback";
471 if(IsEqualGUID(&DSDEVID_DefaultVoicePlayback, pGuid))
472 return "DSDEVID_DefaultVoicePlayback";
473 if(IsEqualGUID(&DSDEVID_DefaultCapture, pGuid))
474 return "DSDEVID_DefaultCapture";
475 if(IsEqualGUID(&DSDEVID_DefaultVoiceCapture, pGuid))
476 return "DSDEVID_DefaultVoiceCapture";
477 return debugstr_guid(pGuid);
480 static HRESULT get_mmdevenum(IMMDeviceEnumerator **devenum)
482 HRESULT hr, init_hr;
484 init_hr = CoInitialize(NULL);
486 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
487 CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)devenum);
488 if(FAILED(hr))
490 if(SUCCEEDED(init_hr))
491 CoUninitialize();
492 *devenum = NULL;
493 ERR("CoCreateInstance failed: %08lx\n", hr);
494 return hr;
497 return init_hr;
500 static void release_mmdevenum(IMMDeviceEnumerator *devenum, HRESULT init_hr)
502 IMMDeviceEnumerator_Release(devenum);
503 if(SUCCEEDED(init_hr))
504 CoUninitialize();
507 static HRESULT get_mmdevice_guid(IMMDevice *device, IPropertyStore *ps, GUID *guid)
509 PROPVARIANT pv;
510 HRESULT hr;
512 if(ps)
513 IPropertyStore_AddRef(ps);
514 else
516 hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
517 if(FAILED(hr))
519 WARN("OpenPropertyStore failed: %08lx\n", hr);
520 return hr;
524 PropVariantInit(&pv);
526 hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_GUID, &pv);
527 if(FAILED(hr))
529 IPropertyStore_Release(ps);
530 WARN("GetValue(GUID) failed: %08lx\n", hr);
531 return hr;
534 CLSIDFromString(pv.pwszVal, guid);
536 PropVariantClear(&pv);
537 IPropertyStore_Release(ps);
539 return S_OK;
543 static BOOL send_device(IMMDevice *device, const GUID *defguid, LPDSENUMCALLBACKW cb, void *user)
545 IPropertyStore *ps;
546 PROPVARIANT pv;
547 BOOL keep_going;
548 HRESULT hr;
549 GUID guid;
551 PropVariantInit(&pv);
553 hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
554 if(FAILED(hr))
556 WARN("OpenPropertyStore failed: %08lx\n", hr);
557 return TRUE;
560 hr = get_mmdevice_guid(device, ps, &guid);
561 if(FAILED(hr) || (defguid && IsEqualGUID(defguid, &guid)))
563 IPropertyStore_Release(ps);
564 return TRUE;
567 hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv);
568 if(FAILED(hr))
570 IPropertyStore_Release(ps);
571 WARN("GetValue(FriendlyName) failed: %08lx\n", hr);
572 return TRUE;
575 TRACE("Calling back with %s (%ls)\n", debugstr_guid(&guid), pv.pwszVal);
577 keep_going = cb(&guid, pv.pwszVal, wine_vxd_drv, user);
579 PropVariantClear(&pv);
580 IPropertyStore_Release(ps);
582 return keep_going;
585 HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device)
587 IMMDeviceEnumerator *devenum;
588 IMMDeviceCollection *coll;
589 UINT count, i;
590 HRESULT hr, init_hr;
592 init_hr = get_mmdevenum(&devenum);
593 if(!devenum) return init_hr;
595 hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flow, DEVICE_STATE_ACTIVE, &coll);
596 if(FAILED(hr))
598 WARN("EnumAudioEndpoints failed: %08lx\n", hr);
599 release_mmdevenum(devenum, init_hr);
600 return hr;
603 hr = IMMDeviceCollection_GetCount(coll, &count);
604 if(FAILED(hr))
606 IMMDeviceCollection_Release(coll);
607 release_mmdevenum(devenum, init_hr);
608 WARN("GetCount failed: %08lx\n", hr);
609 return hr;
612 for(i = 0; i < count;++i)
614 GUID guid;
616 hr = IMMDeviceCollection_Item(coll, i, device);
617 if(FAILED(hr)) continue;
619 hr = get_mmdevice_guid(*device, NULL, &guid);
620 if(FAILED(hr))
622 IMMDevice_Release(*device);
623 continue;
626 if(IsEqualGUID(&guid, tgt))
628 IMMDeviceCollection_Release(coll);
629 release_mmdevenum(devenum, init_hr);
630 return DS_OK;
633 IMMDevice_Release(*device);
636 WARN("No device with GUID %s found!\n", debugstr_guid(tgt));
638 IMMDeviceCollection_Release(coll);
639 release_mmdevenum(devenum, init_hr);
641 return DSERR_INVALIDPARAM;
644 /* S_FALSE means the callback returned FALSE at some point
645 * S_OK means the callback always returned TRUE */
646 HRESULT enumerate_mmdevices(EDataFlow flow, LPDSENUMCALLBACKW cb, void *user)
648 static const WCHAR primary_desc[] = L"Primary Sound Driver";
650 IMMDeviceEnumerator *devenum;
651 IMMDeviceCollection *coll;
652 GUID defguid = GUID_NULL;
653 UINT count, i;
654 BOOL keep_going;
655 HRESULT hr, init_hr;
657 init_hr = get_mmdevenum(&devenum);
658 if(!devenum) return init_hr;
660 hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flow, DEVICE_STATE_ACTIVE, &coll);
661 if(FAILED(hr))
663 release_mmdevenum(devenum, init_hr);
664 WARN("EnumAudioEndpoints failed: %08lx\n", hr);
665 return DS_OK;
668 hr = IMMDeviceCollection_GetCount(coll, &count);
669 if(FAILED(hr))
671 IMMDeviceCollection_Release(coll);
672 release_mmdevenum(devenum, init_hr);
673 WARN("GetCount failed: %08lx\n", hr);
674 return DS_OK;
677 if(count == 0)
679 IMMDeviceCollection_Release(coll);
680 release_mmdevenum(devenum, init_hr);
681 return DS_OK;
684 TRACE("Calling back with NULL (%ls)\n", primary_desc);
685 keep_going = cb(NULL, primary_desc, L"", user);
687 /* always send the default device first */
688 if(keep_going)
690 IMMDevice *device;
691 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flow, eMultimedia, &device);
692 if(SUCCEEDED(hr))
694 keep_going = send_device(device, NULL, cb, user);
695 get_mmdevice_guid(device, NULL, &defguid);
696 IMMDevice_Release(device);
700 for(i = 0;keep_going && i < count;++i)
702 IMMDevice *device;
704 hr = IMMDeviceCollection_Item(coll, i, &device);
705 if(FAILED(hr))
707 WARN("Item failed: %08lx\n", hr);
708 continue;
711 keep_going = send_device(device, &defguid, cb, user);
713 IMMDevice_Release(device);
715 IMMDeviceCollection_Release(coll);
717 release_mmdevenum(devenum, init_hr);
719 return keep_going ? S_OK : S_FALSE;
722 /***************************************************************************
723 * GetDeviceID [DSOUND.9]
725 * Retrieves unique identifier of default device specified
727 * PARAMS
728 * pGuidSrc [I] Address of device GUID.
729 * pGuidDest [O] Address to receive unique device GUID.
731 * RETURNS
732 * Success: DS_OK
733 * Failure: DSERR_INVALIDPARAM
735 * NOTES
736 * pGuidSrc is a valid device GUID or DSDEVID_DefaultPlayback,
737 * DSDEVID_DefaultCapture, DSDEVID_DefaultVoicePlayback, or
738 * DSDEVID_DefaultVoiceCapture.
739 * Returns pGuidSrc if pGuidSrc is a valid device or the device
740 * GUID for the specified constants.
742 DECLSPEC_EXPORT HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest)
744 IMMDeviceEnumerator *devenum;
745 EDataFlow flow = (EDataFlow)-1;
746 ERole role = (ERole)-1;
747 HRESULT hr, init_hr;
749 TRACE("(%s, %p)\n", get_device_id(pGuidSrc), pGuidDest);
751 if(!pGuidSrc || !pGuidDest)
752 return DSERR_INVALIDPARAM;
754 init_hr = get_mmdevenum(&devenum);
755 if(!devenum) return init_hr;
757 if(IsEqualGUID(&DSDEVID_DefaultPlayback, pGuidSrc)){
758 role = eMultimedia;
759 flow = eRender;
760 }else if(IsEqualGUID(&DSDEVID_DefaultVoicePlayback, pGuidSrc)){
761 role = eCommunications;
762 flow = eRender;
763 }else if(IsEqualGUID(&DSDEVID_DefaultCapture, pGuidSrc)){
764 role = eMultimedia;
765 flow = eCapture;
766 }else if(IsEqualGUID(&DSDEVID_DefaultVoiceCapture, pGuidSrc)){
767 role = eCommunications;
768 flow = eCapture;
771 if(role != (ERole)-1 && flow != (EDataFlow)-1)
773 IMMDevice *device;
775 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flow, role, &device);
776 if(FAILED(hr))
778 WARN("GetDefaultAudioEndpoint failed: %08lx\n", hr);
779 release_mmdevenum(devenum, init_hr);
780 return DSERR_NODRIVER;
783 hr = get_mmdevice_guid(device, NULL, pGuidDest);
784 IMMDevice_Release(device);
786 release_mmdevenum(devenum, init_hr);
788 return hr;
791 release_mmdevenum(devenum, init_hr);
793 *pGuidDest = *pGuidSrc;
795 return DS_OK;
799 struct morecontext {
800 LPDSENUMCALLBACKA callA;
801 LPVOID data;
804 static BOOL CALLBACK w_to_a_callback(LPGUID guid, LPCWSTR descW, LPCWSTR modW, LPVOID data)
806 struct morecontext *context = data;
807 char *descA, *modA;
808 int dlen, mlen;
809 BOOL ret;
811 dlen = WideCharToMultiByte(CP_ACP, 0, descW, -1, NULL, 0, NULL, NULL);
812 mlen = WideCharToMultiByte(CP_ACP, 0, modW, -1, NULL, 0, NULL, NULL);
813 if(dlen < 0 || mlen < 0) return FALSE;
815 descA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dlen+mlen+2);
816 if(!descA) return FALSE;
817 modA = descA + dlen+1;
819 WideCharToMultiByte(CP_ACP, 0, descW, -1, descA, dlen, NULL, NULL);
820 WideCharToMultiByte(CP_ACP, 0, modW, -1, modA, mlen, NULL, NULL);
822 ret = context->callA(guid, descA, modA, context->data);
824 HeapFree(GetProcessHeap(), 0, descA);
825 return ret;
828 /***************************************************************************
829 * DirectSoundEnumerateA [DSOUND.2]
831 * Enumerate all DirectSound drivers installed in the system
833 * PARAMS
834 * lpDSEnumCallback [I] Address of callback function.
835 * lpContext [I] Address of user defined context passed to callback function.
837 * RETURNS
838 * Success: DS_OK
839 * Failure: DSERR_INVALIDPARAM
841 DECLSPEC_EXPORT HRESULT WINAPI DirectSoundEnumerateA(
842 LPDSENUMCALLBACKA lpDSEnumCallback,
843 LPVOID lpContext)
845 struct morecontext context;
847 if(lpDSEnumCallback == NULL)
849 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
850 return DSERR_INVALIDPARAM;
853 context.callA = lpDSEnumCallback;
854 context.data = lpContext;
856 return DirectSoundEnumerateW(w_to_a_callback, &context);
860 /***************************************************************************
861 * DirectSoundEnumerateW [DSOUND.3]
863 * Enumerate all DirectSound drivers installed in the system
865 * PARAMS
866 * lpDSEnumCallback [I] Address of callback function.
867 * lpContext [I] Address of user defined context passed to callback function.
869 * RETURNS
870 * Success: DS_OK
871 * Failure: DSERR_INVALIDPARAM
873 DECLSPEC_EXPORT HRESULT WINAPI DirectSoundEnumerateW(
874 LPDSENUMCALLBACKW lpDSEnumCallback,
875 LPVOID lpContext )
877 HRESULT hr;
879 TRACE("(%p, %p)\n", lpDSEnumCallback, lpContext);
881 if(lpDSEnumCallback == NULL)
883 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
884 return DSERR_INVALIDPARAM;
887 hr = enumerate_mmdevices(eRender, lpDSEnumCallback, lpContext);
888 return SUCCEEDED(hr) ? DS_OK : hr;
891 /***************************************************************************
892 * DirectSoundCaptureEnumerateA [DSOUND.7]
894 * Enumerate all DirectSound drivers installed in the system.
896 * PARAMS
897 * lpDSEnumCallback [I] Address of callback function.
898 * lpContext [I] Address of user defined context passed to callback function.
900 * RETURNS
901 * Success: DS_OK
902 * Failure: DSERR_INVALIDPARAM
904 DECLSPEC_EXPORT HRESULT WINAPI DirectSoundCaptureEnumerateA(
905 LPDSENUMCALLBACKA lpDSEnumCallback,
906 LPVOID lpContext)
908 struct morecontext context;
910 if(lpDSEnumCallback == NULL)
912 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
913 return DSERR_INVALIDPARAM;
916 context.callA = lpDSEnumCallback;
917 context.data = lpContext;
919 return DirectSoundCaptureEnumerateW(w_to_a_callback, &context);
922 /***************************************************************************
923 * DirectSoundCaptureEnumerateW [DSOUND.8]
925 * Enumerate all DirectSound drivers installed in the system.
927 * PARAMS
928 * lpDSEnumCallback [I] Address of callback function.
929 * lpContext [I] Address of user defined context passed to callback function.
931 * RETURNS
932 * Success: DS_OK
933 * Failure: DSERR_INVALIDPARAM
935 DECLSPEC_EXPORT HRESULT WINAPI DirectSoundCaptureEnumerateW(
936 LPDSENUMCALLBACKW lpDSEnumCallback,
937 LPVOID lpContext)
939 HRESULT hr;
941 TRACE("(%p, %p)\n", lpDSEnumCallback, lpContext );
943 if(lpDSEnumCallback == NULL)
945 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
946 return DSERR_INVALIDPARAM;
949 hr = enumerate_mmdevices(eCapture, lpDSEnumCallback, lpContext);
950 return SUCCEEDED(hr) ? DS_OK : hr;
953 /*******************************************************************************
954 * DirectSoundCreate (DSOUND.1)
956 * Creates and initializes a DirectSound interface.
958 * PARAMS
959 * lpcGUID [I] Address of the GUID that identifies the sound device.
960 * ppDS [O] Address of a variable to receive the interface pointer.
961 * pUnkOuter [I] Must be NULL.
963 * RETURNS
964 * Success: DS_OK
965 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
966 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
968 DECLSPEC_EXPORT HRESULT WINAPI
969 DirectSoundCreate(LPCGUID lpcGUID, IDirectSound **ppDS, IUnknown *pUnkOuter)
971 HRESULT hr;
972 void *pDS;
974 TRACE("(%s, %p, %p)\n", debugstr_guid(lpcGUID), ppDS, pUnkOuter);
976 if (ppDS == NULL) {
977 WARN("invalid parameter: ppDS == NULL\n");
978 return DSERR_INVALIDPARAM;
980 *ppDS = NULL;
982 if (pUnkOuter != NULL) {
983 WARN("invalid parameter: pUnkOuter != NULL\n");
984 return DSERR_INVALIDPARAM;
987 hr = DSOUND_Create(&IID_IDirectSound, &pDS);
988 if(SUCCEEDED(hr))
990 *ppDS = pDS;
991 hr = IDirectSound_Initialize(*ppDS, lpcGUID);
992 if(FAILED(hr))
994 IDirectSound_Release(*ppDS);
995 *ppDS = NULL;
999 return hr;
1002 /*******************************************************************************
1003 * DirectSoundCreate8 (DSOUND.11)
1005 * Creates and initializes a DirectSound8 interface.
1007 * PARAMS
1008 * lpcGUID [I] Address of the GUID that identifies the sound device.
1009 * ppDS [O] Address of a variable to receive the interface pointer.
1010 * pUnkOuter [I] Must be NULL.
1012 * RETURNS
1013 * Success: DS_OK
1014 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1015 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1017 DECLSPEC_EXPORT HRESULT WINAPI
1018 DirectSoundCreate8(LPCGUID lpcGUID, IDirectSound8 **ppDS, IUnknown *pUnkOuter)
1020 HRESULT hr;
1021 void *pDS;
1023 TRACE("(%s, %p, %p)\n", debugstr_guid(lpcGUID), ppDS, pUnkOuter);
1025 if (ppDS == NULL) {
1026 WARN("invalid parameter: ppDS == NULL\n");
1027 return DSERR_INVALIDPARAM;
1029 *ppDS = NULL;
1031 if (pUnkOuter != NULL) {
1032 WARN("invalid parameter: pUnkOuter != NULL\n");
1033 return DSERR_INVALIDPARAM;
1036 hr = DSOUND_Create8(&IID_IDirectSound8, &pDS);
1037 if(SUCCEEDED(hr))
1039 *ppDS = pDS;
1040 hr = IDirectSound8_Initialize(*ppDS, lpcGUID);
1041 if(FAILED(hr))
1043 IDirectSound8_Release(*ppDS);
1044 *ppDS = NULL;
1048 return hr;
1051 /***************************************************************************
1052 * DirectSoundCaptureCreate [DSOUND.6]
1054 * Create and initialize a DirectSoundCapture interface.
1056 * PARAMS
1057 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1058 * lplpDSC [O] Address of a variable to receive the interface pointer.
1059 * pUnkOuter [I] Must be NULL.
1061 * RETURNS
1062 * Success: DS_OK
1063 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1064 * DSERR_OUTOFMEMORY
1066 * NOTES
1067 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1068 * or NULL for the default device or DSDEVID_DefaultCapture or
1069 * DSDEVID_DefaultVoiceCapture.
1071 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1073 DECLSPEC_EXPORT HRESULT WINAPI
1074 DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter)
1076 HRESULT hr;
1077 void *pDSC;
1079 TRACE("(%s, %p, %p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1081 if(pUnkOuter)
1083 WARN("invalid parameter: pUnkOuter != NULL\n");
1084 return DSERR_NOAGGREGATION;
1087 if(ppDSC == NULL)
1089 WARN("invalid parameter: ppDSC == NULL\n");
1090 return DSERR_INVALIDPARAM;
1092 *ppDSC = NULL;
1094 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
1095 if(SUCCEEDED(hr))
1097 *ppDSC = pDSC;
1098 hr = IDirectSoundCapture_Initialize(*ppDSC, lpcGUID);
1099 if(FAILED(hr))
1101 IDirectSoundCapture_Release(*ppDSC);
1102 *ppDSC = NULL;
1106 return hr;
1109 /***************************************************************************
1110 * DirectSoundCaptureCreate8 [DSOUND.12]
1112 * Create and initialize a DirectSoundCapture interface.
1114 * PARAMS
1115 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1116 * lplpDSC [O] Address of a variable to receive the interface pointer.
1117 * pUnkOuter [I] Must be NULL.
1119 * RETURNS
1120 * Success: DS_OK
1121 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1122 * DSERR_OUTOFMEMORY
1124 * NOTES
1125 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1126 * or NULL for the default device or DSDEVID_DefaultCapture or
1127 * DSDEVID_DefaultVoiceCapture.
1129 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1131 DECLSPEC_EXPORT HRESULT WINAPI
1132 DirectSoundCaptureCreate8(LPCGUID lpcGUID, IDirectSoundCapture8 **ppDSC8, IUnknown *pUnkOuter)
1134 HRESULT hr;
1135 void *pDSC8;
1137 TRACE("(%s, %p, %p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1139 if(pUnkOuter)
1141 WARN("invalid parameter: pUnkOuter != NULL\n");
1142 return DSERR_NOAGGREGATION;
1145 if(ppDSC8 == NULL)
1147 WARN("invalid parameter: ppDSC8 == NULL\n");
1148 return DSERR_INVALIDPARAM;
1150 *ppDSC8 = NULL;
1152 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture, &pDSC8);
1153 if(SUCCEEDED(hr))
1155 *ppDSC8 = pDSC8;
1156 hr = IDirectSoundCapture_Initialize(*ppDSC8, lpcGUID);
1157 if(FAILED(hr))
1159 IDirectSoundCapture_Release(*ppDSC8);
1160 *ppDSC8 = NULL;
1164 return hr;
1167 /*******************************************************************************
1168 * DirectSound ClassFactory
1171 typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj);
1173 typedef struct {
1174 IClassFactory IClassFactory_iface;
1175 LONG ref;
1176 REFCLSID rclsid;
1177 FnCreateInstance pfnCreateInstance;
1178 } IClassFactoryImpl;
1180 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1182 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
1185 static HRESULT WINAPI DSCF_QueryInterface(LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj)
1187 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1188 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
1189 if (ppobj == NULL)
1190 return E_POINTER;
1191 if (IsEqualIID(riid, &IID_IUnknown) ||
1192 IsEqualIID(riid, &IID_IClassFactory))
1194 *ppobj = iface;
1195 IUnknown_AddRef(iface);
1196 return S_OK;
1198 *ppobj = NULL;
1199 return E_NOINTERFACE;
1202 static ULONG WINAPI DSCF_AddRef(LPCLASSFACTORY iface)
1204 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1205 ULONG ref = InterlockedIncrement(&(This->ref));
1206 TRACE("(%p) ref was %lu\n", This, ref - 1);
1207 return ref;
1210 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface)
1212 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1213 ULONG ref = InterlockedDecrement(&(This->ref));
1214 TRACE("(%p) ref was %lu\n", This, ref + 1);
1215 /* static class, won't be freed */
1216 return ref;
1219 static HRESULT WINAPI DSCF_CreateInstance(
1220 LPCLASSFACTORY iface,
1221 LPUNKNOWN pOuter,
1222 REFIID riid,
1223 LPVOID *ppobj)
1225 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1226 TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj);
1228 if (pOuter)
1229 return CLASS_E_NOAGGREGATION;
1231 if (ppobj == NULL) {
1232 WARN("invalid parameter\n");
1233 return DSERR_INVALIDPARAM;
1235 *ppobj = NULL;
1236 return This->pfnCreateInstance(riid, ppobj);
1239 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
1241 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1242 FIXME("(%p, %d) stub!\n", This, dolock);
1243 return S_OK;
1246 static const IClassFactoryVtbl DSCF_Vtbl = {
1247 DSCF_QueryInterface,
1248 DSCF_AddRef,
1249 DSCF_Release,
1250 DSCF_CreateInstance,
1251 DSCF_LockServer
1254 static IClassFactoryImpl DSOUND_CF[] = {
1255 { {&DSCF_Vtbl}, 1, &CLSID_DirectSound, DSOUND_Create },
1256 { {&DSCF_Vtbl}, 1, &CLSID_DirectSound8, DSOUND_Create8 },
1257 { {&DSCF_Vtbl}, 1, &CLSID_DirectSoundCapture, DSOUND_CaptureCreate },
1258 { {&DSCF_Vtbl}, 1, &CLSID_DirectSoundCapture8, DSOUND_CaptureCreate8 },
1259 { {&DSCF_Vtbl}, 1, &CLSID_DirectSoundFullDuplex, DSOUND_FullDuplexCreate },
1260 { {&DSCF_Vtbl}, 1, &CLSID_DirectSoundPrivate, IKsPrivatePropertySetImpl_Create },
1261 { {NULL}, 0, NULL, NULL }
1264 /*******************************************************************************
1265 * DllGetClassObject [DSOUND.@]
1266 * Retrieves class object from a DLL object
1268 * NOTES
1269 * Docs say returns STDAPI
1271 * PARAMS
1272 * rclsid [I] CLSID for the class object
1273 * riid [I] Reference to identifier of interface for class object
1274 * ppv [O] Address of variable to receive interface pointer for riid
1276 * RETURNS
1277 * Success: S_OK
1278 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
1279 * E_UNEXPECTED
1281 DECLSPEC_EXPORT HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
1283 int i = 0;
1284 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1286 if (ppv == NULL) {
1287 WARN("invalid parameter\n");
1288 return E_INVALIDARG;
1291 *ppv = NULL;
1293 if (!IsEqualIID(riid, &IID_IClassFactory) &&
1294 !IsEqualIID(riid, &IID_IUnknown)) {
1295 WARN("no interface for %s\n", debugstr_guid(riid));
1296 return E_NOINTERFACE;
1299 while (NULL != DSOUND_CF[i].rclsid) {
1300 if (IsEqualGUID(rclsid, DSOUND_CF[i].rclsid)) {
1301 DSCF_AddRef(&DSOUND_CF[i].IClassFactory_iface);
1302 *ppv = &DSOUND_CF[i].IClassFactory_iface;
1303 return S_OK;
1305 i++;
1308 WARN("No class found for %s\n", debugstr_guid(rclsid));
1309 return CLASS_E_CLASSNOTAVAILABLE;
1313 /*******************************************************************************
1314 * DllCanUnloadNow [DSOUND.4]
1315 * Determines whether the DLL is in use.
1317 * RETURNS
1318 * Success: S_OK
1319 * Failure: S_FALSE
1321 DECLSPEC_EXPORT HRESULT WINAPI DllCanUnloadNow(void)
1323 FIXME("(void): stub\n");
1324 return S_FALSE;
1327 /***********************************************************************
1328 * DllMain (DSOUND.init)
1330 DECLSPEC_EXPORT BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
1332 const WCHAR *wstr;
1334 TRACE("(%p, %lu, %p)\n", hInstDLL, fdwReason, lpvReserved);
1336 switch(fdwReason)
1338 case DLL_PROCESS_ATTACH:
1339 LogFile = stderr;
1340 if((wstr=_wgetenv(L"DSOAL_LOGFILE")) != NULL && wstr[0] != 0)
1342 FILE *f = _wfopen(wstr, L"wt");
1343 if(!f) ERR("Failed to open log file %ls\n", wstr);
1344 else LogFile = f;
1347 TRACE("DLL_PROCESS_ATTACH\n");
1348 if(!load_libopenal())
1349 return FALSE;
1350 TlsThreadPtr = TlsAlloc();
1351 /* Increase refcount on dsound by 1 */
1352 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)hInstDLL, &hInstDLL);
1353 break;
1355 case DLL_THREAD_ATTACH:
1356 TRACE("DLL_THREAD_ATTACH\n");
1357 break;
1359 case DLL_THREAD_DETACH:
1360 TRACE("DLL_THREAD_DETACH\n");
1361 if(local_contexts)
1362 set_context(NULL);
1363 break;
1365 case DLL_PROCESS_DETACH:
1366 TRACE("DLL_PROCESS_DETACH\n");
1367 if(openal_handle)
1368 FreeLibrary(openal_handle);
1369 TlsFree(TlsThreadPtr);
1370 if(LogFile != stderr)
1371 fclose(LogFile);
1372 LogFile = stderr;
1373 break;
1375 default:
1376 TRACE("UNKNOWN REASON\n");
1377 break;
1379 return TRUE;
1382 #ifdef __WINESRC__
1383 /***********************************************************************
1384 * DllRegisterServer (DSOUND.@)
1386 HRESULT WINAPI DllRegisterServer(void)
1388 return __wine_register_resources(instance);
1391 /***********************************************************************
1392 * DllUnregisterServer (DSOUND.@)
1394 HRESULT WINAPI DllUnregisterServer(void)
1396 return __wine_unregister_resources(instance);
1398 #endif