dsound: Reimplement rendering devices on mmdevapi.
[wine.git] / dlls / dsound / dsound_main.c
blob681e3984b6fcb33bc204156fde4b3d0968ae4e94
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 #include <stdarg.h>
37 #define COBJMACROS
38 #define NONAMELESSSTRUCT
39 #define NONAMELESSUNION
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winuser.h"
43 #include "winnls.h"
44 #include "winreg.h"
45 #include "mmsystem.h"
46 #include "winternl.h"
47 #include "mmddk.h"
48 #include "wine/debug.h"
49 #include "dsound.h"
50 #include "dsconf.h"
51 #include "ks.h"
52 #include "rpcproxy.h"
53 #include "rpc.h"
54 #include "rpcndr.h"
55 #include "unknwn.h"
56 #include "oleidl.h"
57 #include "shobjidl.h"
59 #include "initguid.h"
60 #include "ksmedia.h"
61 #include "propkey.h"
62 #include "devpkey.h"
64 #include "dsound_private.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
68 struct list DSOUND_renderers = LIST_INIT(DSOUND_renderers);
69 CRITICAL_SECTION DSOUND_renderers_lock;
71 GUID DSOUND_renderer_guids[MAXWAVEDRIVERS];
72 GUID DSOUND_capture_guids[MAXWAVEDRIVERS];
74 static IMMDeviceEnumerator *g_devenum;
75 static CRITICAL_SECTION g_devenum_lock;
76 static HANDLE g_devenum_thread;
78 HRESULT mmErr(UINT err)
80 switch(err) {
81 case MMSYSERR_NOERROR:
82 return DS_OK;
83 case MMSYSERR_ALLOCATED:
84 return DSERR_ALLOCATED;
85 case MMSYSERR_ERROR:
86 case MMSYSERR_INVALHANDLE:
87 case WAVERR_STILLPLAYING:
88 return DSERR_GENERIC; /* FIXME */
89 case MMSYSERR_NODRIVER:
90 return DSERR_NODRIVER;
91 case MMSYSERR_NOMEM:
92 return DSERR_OUTOFMEMORY;
93 case MMSYSERR_INVALPARAM:
94 case WAVERR_BADFORMAT:
95 case WAVERR_UNPREPARED:
96 return DSERR_INVALIDPARAM;
97 case MMSYSERR_NOTSUPPORTED:
98 return DSERR_UNSUPPORTED;
99 default:
100 FIXME("Unknown MMSYS error %d\n",err);
101 return DSERR_GENERIC;
105 /* All default settings, you most likely don't want to touch these, see wiki on UsefulRegistryKeys */
106 int ds_emuldriver = 0;
107 int ds_hel_buflen = 32768 * 2;
108 int ds_snd_queue_max = 10;
109 int ds_snd_shadow_maxsize = 2;
110 int ds_default_sample_rate = 44100;
111 int ds_default_bits_per_sample = 16;
112 static int ds_default_playback;
113 static int ds_default_capture;
114 static HINSTANCE instance;
117 * Get a config key from either the app-specific or the default config
120 static inline DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
121 char *buffer, DWORD size )
123 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
124 if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
125 return ERROR_FILE_NOT_FOUND;
130 * Setup the dsound options.
133 void setup_dsound_options(void)
135 char buffer[MAX_PATH+16];
136 HKEY hkey, appkey = 0;
137 DWORD len;
139 buffer[MAX_PATH]='\0';
141 /* @@ Wine registry key: HKCU\Software\Wine\DirectSound */
142 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\DirectSound", &hkey )) hkey = 0;
144 len = GetModuleFileNameA( 0, buffer, MAX_PATH );
145 if (len && len < MAX_PATH)
147 HKEY tmpkey;
148 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectSound */
149 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
151 char *p, *appname = buffer;
152 if ((p = strrchr( appname, '/' ))) appname = p + 1;
153 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
154 strcat( appname, "\\DirectSound" );
155 TRACE("appname = [%s]\n", appname);
156 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
157 RegCloseKey( tmpkey );
161 /* get options */
163 if (!get_config_key( hkey, appkey, "EmulDriver", buffer, MAX_PATH ))
164 ds_emuldriver = strcmp(buffer, "N");
166 if (!get_config_key( hkey, appkey, "HelBuflen", buffer, MAX_PATH ))
167 ds_hel_buflen = atoi(buffer);
169 if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH ))
170 ds_snd_queue_max = atoi(buffer);
172 if (!get_config_key( hkey, appkey, "DefaultPlayback", buffer, MAX_PATH ))
173 ds_default_playback = atoi(buffer);
175 if (!get_config_key( hkey, appkey, "MaxShadowSize", buffer, MAX_PATH ))
176 ds_snd_shadow_maxsize = atoi(buffer);
178 if (!get_config_key( hkey, appkey, "DefaultCapture", buffer, MAX_PATH ))
179 ds_default_capture = atoi(buffer);
181 if (!get_config_key( hkey, appkey, "DefaultSampleRate", buffer, MAX_PATH ))
182 ds_default_sample_rate = atoi(buffer);
184 if (!get_config_key( hkey, appkey, "DefaultBitsPerSample", buffer, MAX_PATH ))
185 ds_default_bits_per_sample = atoi(buffer);
187 if (appkey) RegCloseKey( appkey );
188 if (hkey) RegCloseKey( hkey );
190 TRACE("ds_emuldriver = %d\n", ds_emuldriver);
191 TRACE("ds_hel_buflen = %d\n", ds_hel_buflen);
192 TRACE("ds_snd_queue_max = %d\n", ds_snd_queue_max);
193 TRACE("ds_default_playback = %d\n", ds_default_playback);
194 TRACE("ds_default_capture = %d\n", ds_default_capture);
195 TRACE("ds_default_sample_rate = %d\n", ds_default_sample_rate);
196 TRACE("ds_default_bits_per_sample = %d\n", ds_default_bits_per_sample);
197 TRACE("ds_snd_shadow_maxsize = %d\n", ds_snd_shadow_maxsize);
200 static const char * get_device_id(LPCGUID pGuid)
202 if (IsEqualGUID(&DSDEVID_DefaultPlayback, pGuid))
203 return "DSDEVID_DefaultPlayback";
204 else if (IsEqualGUID(&DSDEVID_DefaultVoicePlayback, pGuid))
205 return "DSDEVID_DefaultVoicePlayback";
206 else if (IsEqualGUID(&DSDEVID_DefaultCapture, pGuid))
207 return "DSDEVID_DefaultCapture";
208 else if (IsEqualGUID(&DSDEVID_DefaultVoiceCapture, pGuid))
209 return "DSDEVID_DefaultVoiceCapture";
210 return debugstr_guid(pGuid);
213 /* The MMDeviceEnumerator object has to be created & destroyed
214 * from the same thread. */
215 static DWORD WINAPI devenum_thread_proc(void *arg)
217 HANDLE evt = arg;
218 HRESULT hr;
219 MSG msg;
221 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
222 if(FAILED(hr)){
223 ERR("CoInitializeEx failed: %08x\n", hr);
224 return 1;
227 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
228 CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&g_devenum);
229 if(FAILED(hr)){
230 ERR("CoCreateInstance failed: %08x\n", hr);
231 CoUninitialize();
232 return 1;
235 SetEvent(evt);
237 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
239 while(GetMessageW(&msg, NULL, 0, 0)){
240 if(msg.hwnd)
241 DispatchMessageW(&msg);
242 else
243 ERR("Unknown message: %04x\n", msg.message);
246 IMMDeviceEnumerator_Release(g_devenum);
247 g_devenum = NULL;
248 CoUninitialize();
250 return 0;
253 static IMMDeviceEnumerator *get_mmdevenum(void)
255 HANDLE events[2];
256 DWORD wait;
258 EnterCriticalSection(&g_devenum_lock);
260 if(g_devenum){
261 LeaveCriticalSection(&g_devenum_lock);
262 return g_devenum;
265 events[0] = CreateEventW(NULL, FALSE, FALSE, NULL);
267 g_devenum_thread = CreateThread(NULL, 0, devenum_thread_proc,
268 events[0], 0, NULL);
269 if(!g_devenum_thread){
270 LeaveCriticalSection(&g_devenum_lock);
271 CloseHandle(events[0]);
272 return NULL;
275 events[1] = g_devenum_thread;
276 wait = WaitForMultipleObjects(2, events, FALSE, INFINITE);
277 CloseHandle(events[0]);
278 if(wait != WAIT_OBJECT_0){
279 if(wait == 1 + WAIT_OBJECT_0){
280 CloseHandle(g_devenum_thread);
281 g_devenum_thread = NULL;
283 LeaveCriticalSection(&g_devenum_lock);
284 return NULL;
287 LeaveCriticalSection(&g_devenum_lock);
289 return g_devenum;
292 static HRESULT get_mmdevice_guid(IMMDevice *device, IPropertyStore *ps,
293 GUID *guid)
295 PROPVARIANT pv;
296 HRESULT hr;
298 if(!ps){
299 hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
300 if(FAILED(hr)){
301 WARN("OpenPropertyStore failed: %08x\n", hr);
302 return hr;
304 }else
305 IPropertyStore_AddRef(ps);
307 PropVariantInit(&pv);
309 hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_GUID, &pv);
310 if(FAILED(hr)){
311 IPropertyStore_Release(ps);
312 WARN("GetValue(GUID) failed: %08x\n", hr);
313 return hr;
316 CLSIDFromString(pv.u.pwszVal, guid);
318 PropVariantClear(&pv);
319 IPropertyStore_Release(ps);
321 return S_OK;
324 /***************************************************************************
325 * GetDeviceID [DSOUND.9]
327 * Retrieves unique identifier of default device specified
329 * PARAMS
330 * pGuidSrc [I] Address of device GUID.
331 * pGuidDest [O] Address to receive unique device GUID.
333 * RETURNS
334 * Success: DS_OK
335 * Failure: DSERR_INVALIDPARAM
337 * NOTES
338 * pGuidSrc is a valid device GUID or DSDEVID_DefaultPlayback,
339 * DSDEVID_DefaultCapture, DSDEVID_DefaultVoicePlayback, or
340 * DSDEVID_DefaultVoiceCapture.
341 * Returns pGuidSrc if pGuidSrc is a valid device or the device
342 * GUID for the specified constants.
344 HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest)
346 IMMDeviceEnumerator *devenum;
347 EDataFlow flow = (EDataFlow)-1;
348 ERole role = (ERole)-1;
349 HRESULT hr;
351 TRACE("(%s,%p)\n", get_device_id(pGuidSrc),pGuidDest);
353 if(!pGuidSrc || !pGuidDest)
354 return DSERR_INVALIDPARAM;
356 devenum = get_mmdevenum();
357 if(!devenum)
358 return DSERR_GENERIC;
360 if(IsEqualGUID(&DSDEVID_DefaultPlayback, pGuidSrc)){
361 role = eMultimedia;
362 flow = eRender;
363 }else if(IsEqualGUID(&DSDEVID_DefaultVoicePlayback, pGuidSrc)){
364 role = eCommunications;
365 flow = eRender;
366 }else if(IsEqualGUID(&DSDEVID_DefaultCapture, pGuidSrc)){
367 role = eMultimedia;
368 flow = eCapture;
369 }else if(IsEqualGUID(&DSDEVID_DefaultVoiceCapture, pGuidSrc)){
370 role = eCommunications;
371 flow = eCapture;
374 if(role != (ERole)-1 && flow != (EDataFlow)-1){
375 IMMDevice *device;
377 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum,
378 flow, role, &device);
379 if(FAILED(hr)){
380 WARN("GetDefaultAudioEndpoint failed: %08x\n", hr);
381 return DSERR_NODRIVER;
384 hr = get_mmdevice_guid(device, NULL, pGuidDest);
385 IMMDevice_Release(device);
387 return (hr == S_OK) ? DS_OK : hr;
390 *pGuidDest = *pGuidSrc;
392 return DS_OK;
395 struct morecontext
397 LPDSENUMCALLBACKA callA;
398 LPVOID data;
401 static BOOL CALLBACK a_to_w_callback(LPGUID guid, LPCWSTR descW, LPCWSTR modW, LPVOID data)
403 struct morecontext *context = data;
404 char descA[MAXPNAMELEN], modA[MAXPNAMELEN];
406 WideCharToMultiByte(CP_ACP, 0, descW, -1, descA, sizeof(descA), NULL, NULL);
407 WideCharToMultiByte(CP_ACP, 0, modW, -1, modA, sizeof(modA), NULL, NULL);
409 return context->callA(guid, descA, modA, context->data);
412 /***************************************************************************
413 * DirectSoundEnumerateA [DSOUND.2]
415 * Enumerate all DirectSound drivers installed in the system
417 * PARAMS
418 * lpDSEnumCallback [I] Address of callback function.
419 * lpContext [I] Address of user defined context passed to callback function.
421 * RETURNS
422 * Success: DS_OK
423 * Failure: DSERR_INVALIDPARAM
425 HRESULT WINAPI DirectSoundEnumerateA(
426 LPDSENUMCALLBACKA lpDSEnumCallback,
427 LPVOID lpContext)
429 struct morecontext context;
431 if (lpDSEnumCallback == NULL) {
432 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
433 return DSERR_INVALIDPARAM;
436 context.callA = lpDSEnumCallback;
437 context.data = lpContext;
439 return DirectSoundEnumerateW(a_to_w_callback, &context);
442 HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device)
444 IMMDeviceEnumerator *devenum;
445 IMMDeviceCollection *coll;
446 UINT count, i;
447 HRESULT hr;
449 devenum = get_mmdevenum();
450 if(!devenum)
451 return DSERR_GENERIC;
453 hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flow,
454 DEVICE_STATE_ACTIVE, &coll);
455 if(FAILED(hr)){
456 WARN("EnumAudioEndpoints failed: %08x\n", hr);
457 return hr;
460 hr = IMMDeviceCollection_GetCount(coll, &count);
461 if(FAILED(hr)){
462 IMMDeviceCollection_Release(coll);
463 WARN("GetCount failed: %08x\n", hr);
464 return hr;
467 for(i = 0; i < count; ++i){
468 GUID guid;
470 hr = IMMDeviceCollection_Item(coll, i, device);
471 if(FAILED(hr))
472 continue;
474 hr = get_mmdevice_guid(*device, NULL, &guid);
475 if(FAILED(hr)){
476 IMMDevice_Release(*device);
477 continue;
480 if(IsEqualGUID(&guid, tgt))
481 return DS_OK;
483 IMMDevice_Release(*device);
486 WARN("No device with GUID %s found!\n", wine_dbgstr_guid(tgt));
488 return DSERR_INVALIDPARAM;
491 static HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids,
492 LPDSENUMCALLBACKW cb, void *user)
494 IMMDeviceEnumerator *devenum;
495 IMMDeviceCollection *coll;
496 UINT count, i;
497 BOOL keep_going;
498 HRESULT hr;
500 static const WCHAR primary_desc[] = {'P','r','i','m','a','r','y',' ',
501 'S','o','u','n','d',' ','D','r','i','v','e','r',0};
502 static const WCHAR empty_drv[] = {0};
503 static const WCHAR wine_vxd_drv[] = { 'w','i','n','e','m','m','.',
504 'v','x','d', 0 };
506 devenum = get_mmdevenum();
507 if(!devenum)
508 return DS_OK;
510 hr = IMMDeviceEnumerator_EnumAudioEndpoints(g_devenum, flow,
511 DEVICE_STATE_ACTIVE, &coll);
512 if(FAILED(hr)){
513 WARN("EnumAudioEndpoints failed: %08x\n", hr);
514 return DS_OK;
517 hr = IMMDeviceCollection_GetCount(coll, &count);
518 if(FAILED(hr)){
519 IMMDeviceCollection_Release(coll);
520 WARN("GetCount failed: %08x\n", hr);
521 return DS_OK;
524 if(count == 0)
525 return DS_OK;
527 keep_going = cb(NULL, primary_desc, empty_drv, user);
529 for(i = 0; keep_going && i < count; ++i){
530 IMMDevice *device;
531 IPropertyStore *ps;
532 PROPVARIANT pv;
534 PropVariantInit(&pv);
536 hr = IMMDeviceCollection_Item(coll, i, &device);
537 if(FAILED(hr)){
538 WARN("Item failed: %08x\n", hr);
539 continue;
542 hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
543 if(FAILED(hr)){
544 IMMDevice_Release(device);
545 WARN("OpenPropertyStore failed: %08x\n", hr);
546 continue;
549 hr = get_mmdevice_guid(device, ps, &guids[i]);
550 if(FAILED(hr)){
551 IPropertyStore_Release(ps);
552 IMMDevice_Release(device);
553 continue;
556 hr = IPropertyStore_GetValue(ps,
557 (const PROPERTYKEY *)&DEVPKEY_Device_FriendlyName, &pv);
558 if(FAILED(hr)){
559 IPropertyStore_Release(ps);
560 IMMDevice_Release(device);
561 WARN("GetValue(FriendlyName) failed: %08x\n", hr);
562 continue;
565 keep_going = cb(&guids[i], pv.u.pwszVal, wine_vxd_drv, user);
567 PropVariantClear(&pv);
568 IPropertyStore_Release(ps);
569 IMMDevice_Release(device);
572 IMMDeviceCollection_Release(coll);
574 return DS_OK;
577 /***************************************************************************
578 * DirectSoundEnumerateW [DSOUND.3]
580 * Enumerate all DirectSound drivers installed in the system
582 * PARAMS
583 * lpDSEnumCallback [I] Address of callback function.
584 * lpContext [I] Address of user defined context passed to callback function.
586 * RETURNS
587 * Success: DS_OK
588 * Failure: DSERR_INVALIDPARAM
590 HRESULT WINAPI DirectSoundEnumerateW(
591 LPDSENUMCALLBACKW lpDSEnumCallback,
592 LPVOID lpContext )
594 TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext);
596 if (lpDSEnumCallback == NULL) {
597 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
598 return DSERR_INVALIDPARAM;
601 setup_dsound_options();
603 return enumerate_mmdevices(eRender, DSOUND_renderer_guids,
604 lpDSEnumCallback, lpContext);
607 /***************************************************************************
608 * DirectSoundCaptureEnumerateA [DSOUND.7]
610 * Enumerate all DirectSound drivers installed in the system.
612 * PARAMS
613 * lpDSEnumCallback [I] Address of callback function.
614 * lpContext [I] Address of user defined context passed to callback function.
616 * RETURNS
617 * Success: DS_OK
618 * Failure: DSERR_INVALIDPARAM
620 HRESULT WINAPI DirectSoundCaptureEnumerateA(
621 LPDSENUMCALLBACKA lpDSEnumCallback,
622 LPVOID lpContext)
624 struct morecontext context;
626 if (lpDSEnumCallback == NULL) {
627 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
628 return DSERR_INVALIDPARAM;
631 context.callA = lpDSEnumCallback;
632 context.data = lpContext;
634 return DirectSoundCaptureEnumerateW(a_to_w_callback, &context);
637 /***************************************************************************
638 * DirectSoundCaptureEnumerateW [DSOUND.8]
640 * Enumerate all DirectSound drivers installed in the system.
642 * PARAMS
643 * lpDSEnumCallback [I] Address of callback function.
644 * lpContext [I] Address of user defined context passed to callback function.
646 * RETURNS
647 * Success: DS_OK
648 * Failure: DSERR_INVALIDPARAM
650 HRESULT WINAPI
651 DirectSoundCaptureEnumerateW(
652 LPDSENUMCALLBACKW lpDSEnumCallback,
653 LPVOID lpContext)
655 unsigned devs, wid;
656 DSDRIVERDESC desc;
657 GUID guid;
658 int err;
659 WCHAR wDesc[MAXPNAMELEN];
660 WCHAR wName[MAXPNAMELEN];
662 TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
664 if (lpDSEnumCallback == NULL) {
665 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
666 return DSERR_INVALIDPARAM;
669 setup_dsound_options();
671 devs = waveInGetNumDevs();
672 if (devs > 0) {
673 if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
674 for (wid = 0; wid < devs; ++wid) {
675 if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) {
676 err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
677 if (err == DS_OK) {
678 TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
679 "Primary Sound Capture Driver",desc.szDrvname,lpContext);
680 MultiByteToWideChar( CP_ACP, 0, "Primary Sound Capture Driver", -1,
681 wDesc, sizeof(wDesc)/sizeof(WCHAR) );
682 MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1,
683 wName, sizeof(wName)/sizeof(WCHAR) );
684 wName[(sizeof(wName)/sizeof(WCHAR)) - 1] = '\0';
686 if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE)
687 return DS_OK;
694 for (wid = 0; wid < devs; ++wid) {
695 err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
696 if (err == DS_OK) {
697 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
698 debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext);
699 MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1,
700 wDesc, sizeof(wDesc)/sizeof(WCHAR) );
701 wDesc[(sizeof(wDesc)/sizeof(WCHAR)) - 1] = '\0';
703 MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1,
704 wName, sizeof(wName)/sizeof(WCHAR) );
705 wName[(sizeof(wName)/sizeof(WCHAR)) - 1] = '\0';
707 if (lpDSEnumCallback(&DSOUND_capture_guids[wid], wDesc, wName, lpContext) == FALSE)
708 return DS_OK;
712 return DS_OK;
715 /*******************************************************************************
716 * DirectSound ClassFactory
719 typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj);
721 typedef struct {
722 IClassFactory IClassFactory_iface;
723 REFCLSID rclsid;
724 FnCreateInstance pfnCreateInstance;
725 } IClassFactoryImpl;
727 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
729 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
732 static HRESULT WINAPI
733 DSCF_QueryInterface(LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj)
735 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
736 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
737 if (ppobj == NULL)
738 return E_POINTER;
739 if (IsEqualIID(riid, &IID_IUnknown) ||
740 IsEqualIID(riid, &IID_IClassFactory))
742 *ppobj = iface;
743 IUnknown_AddRef(iface);
744 return S_OK;
746 *ppobj = NULL;
747 return E_NOINTERFACE;
750 static ULONG WINAPI DSCF_AddRef(LPCLASSFACTORY iface)
752 return 2;
755 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface)
757 /* static class, won't be freed */
758 return 1;
761 static HRESULT WINAPI DSCF_CreateInstance(
762 LPCLASSFACTORY iface,
763 LPUNKNOWN pOuter,
764 REFIID riid,
765 LPVOID *ppobj)
767 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
768 TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj);
770 if (pOuter)
771 return CLASS_E_NOAGGREGATION;
773 if (ppobj == NULL) {
774 WARN("invalid parameter\n");
775 return DSERR_INVALIDPARAM;
777 *ppobj = NULL;
778 return This->pfnCreateInstance(riid, ppobj);
781 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
783 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
784 FIXME("(%p, %d) stub!\n", This, dolock);
785 return S_OK;
788 static const IClassFactoryVtbl DSCF_Vtbl = {
789 DSCF_QueryInterface,
790 DSCF_AddRef,
791 DSCF_Release,
792 DSCF_CreateInstance,
793 DSCF_LockServer
796 static IClassFactoryImpl DSOUND_CF[] = {
797 { { &DSCF_Vtbl }, &CLSID_DirectSound, (FnCreateInstance)DSOUND_Create },
798 { { &DSCF_Vtbl }, &CLSID_DirectSound8, (FnCreateInstance)DSOUND_Create8 },
799 { { &DSCF_Vtbl }, &CLSID_DirectSoundCapture, (FnCreateInstance)DSOUND_CaptureCreate },
800 { { &DSCF_Vtbl }, &CLSID_DirectSoundCapture8, (FnCreateInstance)DSOUND_CaptureCreate8 },
801 { { &DSCF_Vtbl }, &CLSID_DirectSoundFullDuplex, (FnCreateInstance)DSOUND_FullDuplexCreate },
802 { { &DSCF_Vtbl }, &CLSID_DirectSoundPrivate, (FnCreateInstance)IKsPrivatePropertySetImpl_Create },
803 { { NULL }, NULL, NULL }
806 /*******************************************************************************
807 * DllGetClassObject [DSOUND.@]
808 * Retrieves class object from a DLL object
810 * NOTES
811 * Docs say returns STDAPI
813 * PARAMS
814 * rclsid [I] CLSID for the class object
815 * riid [I] Reference to identifier of interface for class object
816 * ppv [O] Address of variable to receive interface pointer for riid
818 * RETURNS
819 * Success: S_OK
820 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
821 * E_UNEXPECTED
823 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
825 int i = 0;
826 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
828 if (ppv == NULL) {
829 WARN("invalid parameter\n");
830 return E_INVALIDARG;
833 *ppv = NULL;
835 if (!IsEqualIID(riid, &IID_IClassFactory) &&
836 !IsEqualIID(riid, &IID_IUnknown)) {
837 WARN("no interface for %s\n", debugstr_guid(riid));
838 return E_NOINTERFACE;
841 while (NULL != DSOUND_CF[i].rclsid) {
842 if (IsEqualGUID(rclsid, DSOUND_CF[i].rclsid)) {
843 DSCF_AddRef(&DSOUND_CF[i].IClassFactory_iface);
844 *ppv = &DSOUND_CF[i];
845 return S_OK;
847 i++;
850 WARN("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid),
851 debugstr_guid(riid), ppv);
852 return CLASS_E_CLASSNOTAVAILABLE;
856 /*******************************************************************************
857 * DllCanUnloadNow [DSOUND.4]
858 * Determines whether the DLL is in use.
860 * RETURNS
861 * Can unload now: S_OK
862 * Cannot unload now (the DLL is still active): S_FALSE
864 HRESULT WINAPI DllCanUnloadNow(void)
866 return S_FALSE;
869 #define INIT_GUID(guid, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
870 guid.Data1 = l; guid.Data2 = w1; guid.Data3 = w2; \
871 guid.Data4[0] = b1; guid.Data4[1] = b2; guid.Data4[2] = b3; \
872 guid.Data4[3] = b4; guid.Data4[4] = b5; guid.Data4[5] = b6; \
873 guid.Data4[6] = b7; guid.Data4[7] = b8;
875 /***********************************************************************
876 * DllMain (DSOUND.init)
878 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
880 int i;
881 TRACE("(%p %d %p)\n", hInstDLL, fdwReason, lpvReserved);
883 switch (fdwReason) {
884 case DLL_PROCESS_ATTACH:
885 TRACE("DLL_PROCESS_ATTACH\n");
886 for (i = 0; i < MAXWAVEDRIVERS; i++) {
887 DSOUND_capture[i] = NULL;
888 INIT_GUID(DSOUND_capture_guids[i], 0xbd6dd71b, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i);
890 instance = hInstDLL;
891 DisableThreadLibraryCalls(hInstDLL);
892 /* Increase refcount on dsound by 1 */
893 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)hInstDLL, &hInstDLL);
894 InitializeCriticalSection(&DSOUND_renderers_lock);
895 InitializeCriticalSection(&g_devenum_lock);
896 break;
897 case DLL_PROCESS_DETACH:
898 TRACE("DLL_PROCESS_DETACH\n");
899 break;
900 default:
901 TRACE("UNKNOWN REASON\n");
902 break;
904 return TRUE;
907 /***********************************************************************
908 * DllRegisterServer (DSOUND.@)
910 HRESULT WINAPI DllRegisterServer(void)
912 return __wine_register_resources( instance );
915 /***********************************************************************
916 * DllUnregisterServer (DSOUND.@)
918 HRESULT WINAPI DllUnregisterServer(void)
920 return __wine_unregister_resources( instance );