1 /* DirectDraw Base Functions
3 * Copyright 1997-1999 Marcus Meissner
4 * Copyright 1998 Lionel Ulmer (most of Direct3D stuff)
5 * Copyright 2000-2001 TransGaming Technologies Inc.
7 * This file contains the (internal) driver registration functions,
8 * driver enumeration APIs and DirectDraw creation functions.
23 /* This for all the enumeration and creation of D3D-related objects */
24 #include "ddraw_private.h"
25 #include "debugtools.h"
27 #define MAX_DDRAW_DRIVERS 3
28 static const ddraw_driver* DDRAW_drivers[MAX_DDRAW_DRIVERS];
29 static int DDRAW_num_drivers; /* = 0 */
30 static int DDRAW_default_driver;
32 DEFAULT_DEBUG_CHANNEL(ddraw);
34 /**********************************************************************/
39 } DirectDrawEnumerateProcData;
41 /***********************************************************************
42 * DirectDrawEnumerateExA (DDRAW.@)
44 HRESULT WINAPI DirectDrawEnumerateExA(
45 LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags)
48 TRACE("(%p,%p, %08lx)\n", lpCallback, lpContext, dwFlags);
50 if (TRACE_ON(ddraw)) {
52 if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES)
53 DPRINTF("DDENUM_ATTACHEDSECONDARYDEVICES ");
54 if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES)
55 DPRINTF("DDENUM_DETACHEDSECONDARYDEVICES ");
56 if (dwFlags & DDENUM_NONDISPLAYDEVICES)
57 DPRINTF("DDENUM_NONDISPLAYDEVICES ");
61 for (i=0; i<DDRAW_num_drivers; i++)
63 TRACE("Enumerating %s/%s interface\n",
64 DDRAW_drivers[i]->info->szDriver,
65 DDRAW_drivers[i]->info->szDescription);
67 /* We have to pass NULL from the primary display device.
68 * RoadRage chapter 6's enumeration routine expects it. */
69 if (!lpCallback((DDRAW_default_driver == i) ? NULL
70 :(LPGUID)&DDRAW_drivers[i]->info->guidDeviceIdentifier,
71 (LPSTR)DDRAW_drivers[i]->info->szDescription,
72 (LPSTR)DDRAW_drivers[i]->info->szDriver,
77 /* Unsupported flags */
78 if (dwFlags & DDENUM_NONDISPLAYDEVICES) {
79 FIXME("no non-display devices supported.\n");
81 if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES) {
82 FIXME("no detached secondary devices supported.\n");
88 /***********************************************************************
89 * DirectDrawEnumerateExW (DDRAW.@)
92 static BOOL CALLBACK DirectDrawEnumerateExProcW(
93 GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName,
94 LPVOID lpContext, HMONITOR hm)
98 LPWSTR lpDriverDescriptionW, lpDriverNameW;
99 DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
101 len = MultiByteToWideChar( CP_ACP, 0, lpDriverDescription, -1, NULL, 0 );
102 lpDriverDescriptionW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
103 MultiByteToWideChar( CP_ACP, 0, lpDriverDescription, -1, lpDriverDescriptionW, len );
105 len = MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, NULL, 0 );
106 lpDriverNameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
107 MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, lpDriverNameW, len );
109 bResult = (*(LPDDENUMCALLBACKEXW *) pEPD->lpCallback)(lpGUID, lpDriverDescriptionW,
110 lpDriverNameW, pEPD->lpContext, hm);
112 HeapFree(GetProcessHeap(), 0, lpDriverDescriptionW);
113 HeapFree(GetProcessHeap(), 0, lpDriverNameW);
117 HRESULT WINAPI DirectDrawEnumerateExW(
118 LPDDENUMCALLBACKEXW lpCallback, LPVOID lpContext, DWORD dwFlags)
120 DirectDrawEnumerateProcData epd;
121 epd.lpCallback = (LPVOID) lpCallback;
122 epd.lpContext = lpContext;
124 return DirectDrawEnumerateExA(DirectDrawEnumerateExProcW, (LPVOID) &epd, 0);
127 /***********************************************************************
128 * DirectDrawEnumerateA (DDRAW.@)
131 static BOOL CALLBACK DirectDrawEnumerateProcA(
132 GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName,
133 LPVOID lpContext, HMONITOR hm)
135 DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
137 return ((LPDDENUMCALLBACKA) pEPD->lpCallback)(
138 lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext);
141 HRESULT WINAPI DirectDrawEnumerateA(
142 LPDDENUMCALLBACKA lpCallback, LPVOID lpContext)
144 DirectDrawEnumerateProcData epd;
145 epd.lpCallback = (LPVOID) lpCallback;
146 epd.lpContext = lpContext;
148 return DirectDrawEnumerateExA(DirectDrawEnumerateProcA, (LPVOID) &epd, 0);
151 /***********************************************************************
152 * DirectDrawEnumerateW (DDRAW.@)
155 static BOOL WINAPI DirectDrawEnumerateProcW(
156 GUID *lpGUID, LPWSTR lpDriverDescription, LPWSTR lpDriverName,
157 LPVOID lpContext, HMONITOR hm)
159 DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
161 return ((LPDDENUMCALLBACKW) pEPD->lpCallback)(
162 lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext);
165 HRESULT WINAPI DirectDrawEnumerateW(
166 LPDDENUMCALLBACKW lpCallback, LPVOID lpContext)
168 DirectDrawEnumerateProcData epd;
169 epd.lpCallback = (LPVOID) lpCallback;
170 epd.lpContext = lpContext;
172 return DirectDrawEnumerateExW(DirectDrawEnumerateProcW, (LPVOID) &epd, 0);
175 /***********************************************************************
176 * DirectDrawCreate (DDRAW.@)
179 const ddraw_driver* DDRAW_FindDriver(const GUID* pGUID)
181 static const GUID zeroGUID; /* gets zero-inited */
183 TRACE("(%s)\n", pGUID ? debugstr_guid(pGUID) : "(null)");
185 if (DDRAW_num_drivers == 0) return NULL;
187 if (pGUID == (LPGUID)DDCREATE_EMULATIONONLY
188 || pGUID == (LPGUID)DDCREATE_HARDWAREONLY)
191 if (pGUID == NULL || memcmp(pGUID, &zeroGUID, sizeof(GUID)) == 0)
193 /* Use the default driver. */
194 return DDRAW_drivers[DDRAW_default_driver];
198 /* Look for a matching GUID. */
201 for (i=0; i < DDRAW_num_drivers; i++)
203 if (IsEqualGUID(pGUID,
204 &DDRAW_drivers[i]->info->guidDeviceIdentifier))
208 if (i < DDRAW_num_drivers)
210 return DDRAW_drivers[i];
214 ERR("(%s): did not recognize requested GUID.\n",debugstr_guid(pGUID));
220 static HRESULT DDRAW_Create(
221 LPGUID lpGUID, LPVOID *lplpDD, LPUNKNOWN pUnkOuter, REFIID iid, BOOL ex
223 const ddraw_driver* driver;
227 if (DDRAW_num_drivers == 0)
229 WARN("no DirectDraw drivers registered\n");
230 return DDERR_INVALIDDIRECTDRAWGUID;
233 if (lpGUID == (LPGUID)DDCREATE_EMULATIONONLY
234 || lpGUID == (LPGUID)DDCREATE_HARDWAREONLY)
237 TRACE("(%s,%p,%p)\n",debugstr_guid(lpGUID),lplpDD,pUnkOuter);
239 if (pUnkOuter != NULL)
240 return DDERR_INVALIDPARAMS; /* CLASS_E_NOAGGREGATION? */
242 driver = DDRAW_FindDriver(lpGUID);
243 if (driver == NULL) return DDERR_INVALIDDIRECTDRAWGUID;
245 hr = driver->create(lpGUID, &pDD, pUnkOuter, ex);
246 if (FAILED(hr)) return hr;
248 hr = IDirectDraw7_QueryInterface(pDD, iid, lplpDD);
249 IDirectDraw7_Release(pDD);
253 /***********************************************************************
254 * DirectDrawCreate (DDRAW.@)
256 * Only creates legacy IDirectDraw interfaces.
257 * Cannot create IDirectDraw7 interfaces.
260 HRESULT WINAPI DirectDrawCreate(
261 LPGUID lpGUID, LPDIRECTDRAW* lplpDD, LPUNKNOWN pUnkOuter
263 return DDRAW_Create(lpGUID,(LPVOID*)lplpDD,pUnkOuter,&IID_IDirectDraw,FALSE);
266 /***********************************************************************
267 * DirectDrawCreateEx (DDRAW.@)
269 * Only creates new IDirectDraw7 interfaces.
270 * Supposed to fail if legacy interfaces are requested.
273 HRESULT WINAPI DirectDrawCreateEx(
274 LPGUID lpGUID, LPVOID* lplpDD, REFIID iid, LPUNKNOWN pUnkOuter
276 if (!IsEqualGUID(iid, &IID_IDirectDraw7))
277 return DDERR_INVALIDPARAMS;
279 return DDRAW_Create(lpGUID, lplpDD, pUnkOuter, iid, TRUE);
282 extern HRESULT Uninit_DirectDraw_Create(const GUID*, LPDIRECTDRAW7*,
285 /* This is for the class factory. */
286 static HRESULT DDRAW_CreateDirectDraw(IUnknown* pUnkOuter, REFIID iid,
292 hr = Uninit_DirectDraw_Create(NULL, &pDD, pUnkOuter, TRUE); /* ex? */
293 if (FAILED(hr)) return hr;
295 hr = IDirectDraw7_QueryInterface(pDD, iid, ppObj);
296 IDirectDraw_Release(pDD);
300 /******************************************************************************
301 * DirectDraw ClassFactory
304 ICOM_VFIELD_MULTI(IClassFactory);
307 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID iid,
311 struct object_creation_info
314 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID riid,
318 /* There should be more, but these are the only ones listed in the header
320 extern HRESULT DDRAW_CreateDirectDrawClipper(IUnknown *pUnkOuter, REFIID riid,
323 static const struct object_creation_info object_creation[] =
325 { &CLSID_DirectDraw, DDRAW_CreateDirectDraw },
326 { &CLSID_DirectDraw7, DDRAW_CreateDirectDraw },
327 { &CLSID_DirectDrawClipper, DDRAW_CreateDirectDrawClipper }
330 static HRESULT WINAPI
331 DDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
333 ICOM_THIS(IClassFactoryImpl,iface);
335 if (IsEqualGUID(riid, &IID_IUnknown)
336 || IsEqualGUID(riid, &IID_IClassFactory))
338 IClassFactory_AddRef(iface);
343 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
344 return E_NOINTERFACE;
347 static ULONG WINAPI DDCF_AddRef(LPCLASSFACTORY iface) {
348 ICOM_THIS(IClassFactoryImpl,iface);
349 return ++(This->ref);
352 static ULONG WINAPI DDCF_Release(LPCLASSFACTORY iface) {
353 ICOM_THIS(IClassFactoryImpl,iface);
355 ULONG ref = --This->ref;
358 HeapFree(GetProcessHeap(), 0, This);
364 static HRESULT WINAPI DDCF_CreateInstance(
365 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
367 ICOM_THIS(IClassFactoryImpl,iface);
369 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
371 return This->pfnCreateInstance(pOuter, riid, ppobj);
374 static HRESULT WINAPI DDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
375 ICOM_THIS(IClassFactoryImpl,iface);
376 FIXME("(%p)->(%d),stub!\n",This,dolock);
380 static ICOM_VTABLE(IClassFactory) DDCF_Vtbl =
382 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
390 /*******************************************************************************
391 * DllGetClassObject [DDRAW.@]
392 * Retrieves class object from a DLL object
395 * Docs say returns STDAPI
398 * rclsid [I] CLSID for the class object
399 * riid [I] Reference to identifier of interface for class object
400 * ppv [O] Address of variable to receive interface pointer for riid
404 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
407 DWORD WINAPI DDRAW_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
410 IClassFactoryImpl *factory;
412 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
414 if ( !IsEqualGUID( &IID_IClassFactory, riid )
415 && ! IsEqualGUID( &IID_IUnknown, riid) )
416 return E_NOINTERFACE;
418 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
420 if (IsEqualGUID(object_creation[i].clsid, rclsid))
424 if (i == sizeof(object_creation)/sizeof(object_creation[0]))
426 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
427 return CLASS_E_CLASSNOTAVAILABLE;
430 factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
431 if (factory == NULL) return E_OUTOFMEMORY;
433 ICOM_INIT_INTERFACE(factory, IClassFactory, DDCF_Vtbl);
436 factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
438 *ppv = ICOM_INTERFACE(factory, IClassFactory);
443 /*******************************************************************************
444 * DllCanUnloadNow [DDRAW.@] Determines whether the DLL is in use.
450 DWORD WINAPI DDRAW_DllCanUnloadNow(void) {
451 FIXME("(void): stub\n");
455 /******************************************************************************
459 /* Choose which driver is considered the primary display driver. It will
460 * be created when we get a NULL guid for the DirectDrawCreate(Ex). */
461 static int DDRAW_ChooseDefaultDriver(void)
467 assert(DDRAW_num_drivers > 0);
469 /* This algorithm is really stupid. */
470 for (i=0; i < DDRAW_num_drivers; i++)
472 if (DDRAW_drivers[i]->preference > best_score)
474 best_score = DDRAW_drivers[i]->preference;
479 assert(best_score > 0);
484 BOOL WINAPI DDRAW_DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
486 /* If we were sufficiently cool, DDraw drivers would just be COM
487 * objects, registered with a particular component category. */
489 DDRAW_HAL_Init(hInstDLL, fdwReason, lpv);
490 DDRAW_User_Init(hInstDLL, fdwReason, lpv);
492 if (DDRAW_num_drivers > 0)
493 DDRAW_default_driver = DDRAW_ChooseDefaultDriver();
498 /* Register a direct draw driver. This should be called from your init
499 * function. (That's why there is no locking: your init func is called from
500 * our DllInit, which is serialised.) */
501 void DDRAW_register_driver(const ddraw_driver *driver)
505 for (i = 0; i < DDRAW_num_drivers; i++)
507 if (DDRAW_drivers[i] == driver)
509 ERR("Driver reregistering %p\n", driver);
514 if (DDRAW_num_drivers == sizeof(DDRAW_drivers)/sizeof(DDRAW_drivers[0]))
516 ERR("too many DDRAW drivers\n");
520 DDRAW_drivers[DDRAW_num_drivers++] = driver;
523 /* This totally doesn't belong here. */
524 LONG DDRAW_width_bpp_to_pitch(DWORD width, DWORD bpp)
528 assert(bpp != 0); /* keeps happening... */
530 if (bpp == 15) bpp = 16;
531 pitch = width * (bpp / 8);
532 return pitch + (8 - (pitch % 8)) % 8;