If DirectDrawCreate gets passed a IDirectDraw{2,4,7} interface, get
[wine/multimedia.git] / dlls / ddraw / main.c
bloba7e991ed3b683c9f2569bfe0546250ddb13d6ef7
1 /* DirectDraw Base Functions
3 * Copyright 1997-1999 Marcus Meissner
4 * Copyright 1998 Lionel Ulmer (most of Direct3D stuff)
5 */
7 #include "config.h"
9 #include <unistd.h>
10 #include <assert.h>
11 #include <fcntl.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <stdio.h>
16 #include "winerror.h"
17 #include "heap.h"
18 #include "wine/exception.h"
19 #include "debugtools.h"
21 /* This for all the enumeration and creation of D3D-related objects */
22 #include "ddraw_private.h"
24 #define MAX_DDRAW_DRIVERS 3
25 static ddraw_driver * ddraw_drivers[MAX_DDRAW_DRIVERS];
26 static int nrof_ddraw_drivers = 0;
28 DEFAULT_DEBUG_CHANNEL(ddraw);
30 /* register a direct draw driver. We better not use malloc for we are in
31 * the ELF startup initialisation at this point.
33 void ddraw_register_driver(ddraw_driver *driver) {
34 ddraw_drivers[nrof_ddraw_drivers++] = driver;
36 /* increase MAX_DDRAW_DRIVERS if the line below triggers */
37 assert(nrof_ddraw_drivers <= MAX_DDRAW_DRIVERS);
40 /**********************************************************************/
42 typedef struct {
43 LPVOID lpCallback;
44 LPVOID lpContext;
45 } DirectDrawEnumerateProcData;
47 /***********************************************************************
48 * DirectDrawEnumerateExA (DDRAW.*)
50 HRESULT WINAPI DirectDrawEnumerateExA(
51 LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags)
53 int i;
54 GUID zeroGUID;
55 TRACE("(%p,%p, %08lx)\n", lpCallback, lpContext, dwFlags);
57 if (TRACE_ON(ddraw)) {
58 DPRINTF(" Flags : ");
59 if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES)
60 DPRINTF("DDENUM_ATTACHEDSECONDARYDEVICES ");
61 if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES)
62 DPRINTF("DDENUM_DETACHEDSECONDARYDEVICES ");
63 if (dwFlags & DDENUM_NONDISPLAYDEVICES)
64 DPRINTF("DDENUM_NONDISPLAYDEVICES ");
65 DPRINTF("\n");
67 if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES) {
68 FIXME("no attached secondary devices supported.\n");
69 /*return E_FAIL;*/
72 memset(&zeroGUID,0,sizeof(zeroGUID));
74 /* we have at least one DDRAW driver */
75 if (ddraw_drivers[0]) {
76 if (!lpCallback(
77 &zeroGUID, /* FIXME: or NULL? -MM */
78 "WINE DirectDraw",
79 "display",
80 lpContext,
81 0 /* FIXME: flags not supported here */
83 return DD_OK;
85 /* Invoke callback for what flags we do support */
86 for (i=0;i<MAX_DDRAW_DRIVERS;i++) {
87 if (!ddraw_drivers[i])
88 continue;
89 if (ddraw_drivers[i]->createDDRAW(NULL)) /* !0 is failing */
90 continue;
91 TRACE("Enumerating %s/%s interface\n",ddraw_drivers[i]->name,ddraw_drivers[i]->type);
92 if (!lpCallback(
93 ddraw_drivers[i]->guid,
94 (LPSTR)ddraw_drivers[i]->name,
95 (LPSTR)ddraw_drivers[i]->type,
96 lpContext,
97 0 /* FIXME: flags not supported here */
99 return DD_OK;
101 if (nrof_ddraw_drivers) {
102 TRACE("Enumerating the default interface\n");
103 if (!lpCallback(NULL,"WINE (default)", "display", lpContext, 0))
104 return DD_OK;
107 /* Unsupported flags */
108 if (dwFlags & DDENUM_NONDISPLAYDEVICES) {
109 FIXME("no non-display devices supported.\n");
111 if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES) {
112 FIXME("no detached secondary devices supported.\n");
115 return DD_OK;
118 /***********************************************************************
119 * DirectDrawEnumerateExW (DDRAW.*)
122 static BOOL CALLBACK DirectDrawEnumerateExProcW(
123 GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName,
124 LPVOID lpContext, HMONITOR hm)
126 DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
127 LPWSTR lpDriverDescriptionW =
128 HEAP_strdupAtoW(GetProcessHeap(), 0, lpDriverDescription);
129 LPWSTR lpDriverNameW =
130 HEAP_strdupAtoW(GetProcessHeap(), 0, lpDriverName);
132 BOOL bResult = (*(LPDDENUMCALLBACKEXW *) pEPD->lpCallback)(
133 lpGUID, lpDriverDescriptionW, lpDriverNameW, pEPD->lpContext, hm);
135 HeapFree(GetProcessHeap(), 0, lpDriverDescriptionW);
136 HeapFree(GetProcessHeap(), 0, lpDriverNameW);
137 return bResult;
140 /**********************************************************************/
142 HRESULT WINAPI DirectDrawEnumerateExW(
143 LPDDENUMCALLBACKEXW lpCallback, LPVOID lpContext, DWORD dwFlags)
145 DirectDrawEnumerateProcData epd;
146 epd.lpCallback = (LPVOID) lpCallback;
147 epd.lpContext = lpContext;
149 return DirectDrawEnumerateExA(DirectDrawEnumerateExProcW, (LPVOID) &epd, 0);
152 /***********************************************************************
153 * DirectDrawEnumerateA (DDRAW.*)
156 static BOOL CALLBACK DirectDrawEnumerateProcA(
157 GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName,
158 LPVOID lpContext, HMONITOR hm)
160 DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
162 return ((LPDDENUMCALLBACKA) pEPD->lpCallback)(
163 lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext);
166 /**********************************************************************/
168 HRESULT WINAPI DirectDrawEnumerateA(
169 LPDDENUMCALLBACKA lpCallback, LPVOID lpContext)
171 DirectDrawEnumerateProcData epd;
172 epd.lpCallback = (LPVOID) lpCallback;
173 epd.lpContext = lpContext;
175 return DirectDrawEnumerateExA(DirectDrawEnumerateProcA, (LPVOID) &epd, 0);
178 /***********************************************************************
179 * DirectDrawEnumerateW (DDRAW.*)
182 static BOOL WINAPI DirectDrawEnumerateProcW(
183 GUID *lpGUID, LPWSTR lpDriverDescription, LPWSTR lpDriverName,
184 LPVOID lpContext, HMONITOR hm)
186 DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
188 return ((LPDDENUMCALLBACKW) pEPD->lpCallback)(
189 lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext);
192 /**********************************************************************/
194 HRESULT WINAPI DirectDrawEnumerateW(
195 LPDDENUMCALLBACKW lpCallback, LPVOID lpContext)
197 DirectDrawEnumerateProcData epd;
198 epd.lpCallback = (LPVOID) lpCallback;
199 epd.lpContext = lpContext;
201 return DirectDrawEnumerateExW(DirectDrawEnumerateProcW, (LPVOID) &epd, 0);
204 /******************************************************************************
205 * DirectDraw Window Procedure
207 static LRESULT WINAPI DDWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
209 LRESULT ret;
210 IDirectDrawImpl* ddraw = NULL;
211 DWORD lastError;
213 /* FIXME(ddraw,"(0x%04x,%s,0x%08lx,0x%08lx),stub!\n",(int)hwnd,SPY_GetMsgName(msg),(long)wParam,(long)lParam); */
215 SetLastError( ERROR_SUCCESS );
216 ddraw = (IDirectDrawImpl*)GetPropA( hwnd, ddProp );
217 if( (!ddraw) && ( ( lastError = GetLastError() ) != ERROR_SUCCESS ))
218 ERR("Unable to retrieve this ptr from window. Error %08lx\n",lastError);
220 if( ddraw ) {
221 /* Perform any special direct draw functions */
222 if (msg==WM_PAINT)
223 ddraw->d->paintable = 1;
225 /* Now let the application deal with the rest of this */
226 if( ddraw->d->mainWindow ) {
228 /* Don't think that we actually need to call this but...
229 * might as well be on the safe side of things...
232 /* I changed hwnd to ddraw->d->mainWindow as I did not see why
233 * it should be the procedures of our fake window that gets called
234 * instead of those of the window provided by the application.
235 * And with this patch, mouse clicks work with Monkey Island III
236 * - Lionel
238 ret = DefWindowProcA( ddraw->d->mainWindow, msg, wParam, lParam );
240 if( !ret ) {
241 /* We didn't handle the message - give it to the application */
242 if (ddraw && ddraw->d->mainWindow)
244 WNDPROC winproc = (WNDPROC)GetWindowLongA( ddraw->d->mainWindow, GWL_WNDPROC );
245 ret = CallWindowProcA(winproc, ddraw->d->mainWindow, msg, wParam, lParam );
248 return ret;
249 } /* else FALLTHROUGH */
250 } /* else FALLTHROUGH */
251 return DefWindowProcA(hwnd,msg,wParam,lParam);
254 /***********************************************************************
255 * DirectDrawCreate
257 HRESULT WINAPI DirectDrawCreate(
258 LPGUID lpGUID, LPDIRECTDRAW *lplpDD, LPUNKNOWN pUnkOuter
260 IDirectDrawImpl** ilplpDD=(IDirectDrawImpl**)lplpDD;
261 WNDCLASSA wc;
262 HRESULT ret = 0;
263 int i,drvindex=0;
264 GUID zeroGUID;
266 struct ddraw_driver *ddd = NULL;
268 if (!HIWORD(lpGUID)) lpGUID = NULL;
270 TRACE("(%s,%p,%p)\n",debugstr_guid(lpGUID),ilplpDD,pUnkOuter);
272 memset(&zeroGUID,0,sizeof(zeroGUID));
273 while (1) {
274 ddd = NULL;
275 if ( ( !lpGUID ) ||
276 ( IsEqualGUID( &zeroGUID, lpGUID ) ) ||
277 ( IsEqualGUID( &IID_IDirectDraw, lpGUID ) ) ||
278 ( IsEqualGUID( &IID_IDirectDraw2, lpGUID ) ) ||
279 ( IsEqualGUID( &IID_IDirectDraw4, lpGUID ) ) ||
280 ( IsEqualGUID( &IID_IDirectDraw7, lpGUID ) )
282 /* choose an interface out of the list */
283 for (i=0;i<nrof_ddraw_drivers;i++) {
284 ddraw_driver *xddd = ddraw_drivers[i];
285 if (!xddd)
286 continue;
287 if (!ddd || (ddd->preference<xddd->preference)) {
288 drvindex = i;
289 ddd = xddd;
292 } else {
293 for (i=0;i<nrof_ddraw_drivers;i++) {
294 if (!ddraw_drivers[i])
295 continue;
296 if (IsEqualGUID(ddraw_drivers[i]->guid,lpGUID)) {
297 drvindex = i;
298 ddd = ddraw_drivers[i];
299 break;
303 if (!ddd) {
304 if (!nrof_ddraw_drivers) {
305 ERR("DirectDrawCreate(%s,%p,%p): no DirectDraw drivers compiled in.\n",debugstr_guid(lpGUID),lplpDD,pUnkOuter);
306 return DDERR_NODIRECTDRAWHW;
308 ERR("DirectDrawCreate(%s,%p,%p): did not recognize requested GUID.\n",debugstr_guid(lpGUID),lplpDD,pUnkOuter);
309 return DDERR_INVALIDDIRECTDRAWGUID;
311 TRACE("using \"%s\" driver, calling %p\n",ddd->name,ddd->createDDRAW);
313 ret = ddd->createDDRAW(lplpDD);
314 if (!ret)
315 break;
316 ddraw_drivers[drvindex] = NULL; /* mark this one as unusable */
319 if (IsEqualGUID( &IID_IDirectDraw2, lpGUID ) ||
320 IsEqualGUID( &IID_IDirectDraw4, lpGUID ) ||
321 IsEqualGUID( &IID_IDirectDraw7, lpGUID )
323 LPVOID x;
324 ret = IDirectDraw_QueryInterface(*lplpDD,lpGUID,&x);
325 IDirectDraw_Release(*lplpDD); /* either drop 1 refcount, or release */
326 if (!ret)
327 *lplpDD = x;
328 else
329 return ret;
331 wc.style = CS_GLOBALCLASS;
332 wc.lpfnWndProc = DDWndProc;
333 wc.cbClsExtra = 0;
334 wc.cbWndExtra = 0;
336 /* We can be a child of the desktop since we're really important */
337 wc.hInstance= 0;
338 wc.hIcon = 0;
339 wc.hCursor = (HCURSOR)IDC_ARROWA;
340 wc.hbrBackground = NULL_BRUSH;
341 wc.lpszMenuName = 0;
342 wc.lpszClassName = "WINE_DirectDraw";
343 (*ilplpDD)->d->winclass = RegisterClassA(&wc);
344 return ret;
347 /***********************************************************************
348 * DirectDrawCreateEx
350 HRESULT WINAPI DirectDrawCreateEx(
351 LPGUID lpGUID, LPVOID* lplpDD, REFIID iid, LPUNKNOWN pUnkOuter
353 LPDIRECTDRAW ddraw;
354 HRESULT hres;
356 FIXME("(%p,%p,%s,%p), might be wrong.\n",lpGUID,lplpDD,debugstr_guid(iid),pUnkOuter);
358 hres=DirectDrawCreate(lpGUID,(LPDIRECTDRAW*)&ddraw,pUnkOuter);
359 if (!hres) {
360 hres=IDirectDraw_QueryInterface(ddraw,iid,lplpDD);
361 IDirectDraw_Release(ddraw);
363 return hres;
366 /*******************************************************************************
367 * DirectDraw ClassFactory
369 * Heavily inspired (well, can you say completely copied :-) ) from DirectSound
372 typedef struct {
373 /* IUnknown fields */
374 ICOM_VFIELD(IClassFactory);
375 DWORD ref;
376 } IClassFactoryImpl;
378 static HRESULT WINAPI
379 DDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
380 ICOM_THIS(IClassFactoryImpl,iface);
382 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
383 return E_NOINTERFACE;
386 static ULONG WINAPI
387 DDCF_AddRef(LPCLASSFACTORY iface) {
388 ICOM_THIS(IClassFactoryImpl,iface);
389 return ++(This->ref);
392 static ULONG WINAPI DDCF_Release(LPCLASSFACTORY iface) {
393 ICOM_THIS(IClassFactoryImpl,iface);
394 /* static class, won't be freed */
395 return --(This->ref);
398 static HRESULT WINAPI DDCF_CreateInstance(
399 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
401 ICOM_THIS(IClassFactoryImpl,iface);
403 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
404 if ( ( IsEqualGUID( &IID_IDirectDraw, riid ) ) ||
405 ( IsEqualGUID( &IID_IDirectDraw2, riid ) ) ||
406 ( IsEqualGUID( &IID_IDirectDraw4, riid ) ) ) {
407 /* FIXME: reuse already created DirectDraw if present? */
408 return DirectDrawCreate((LPGUID) riid,(LPDIRECTDRAW*)ppobj,pOuter);
410 return CLASS_E_CLASSNOTAVAILABLE;
413 static HRESULT WINAPI DDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
414 ICOM_THIS(IClassFactoryImpl,iface);
415 FIXME("(%p)->(%d),stub!\n",This,dolock);
416 return S_OK;
419 static ICOM_VTABLE(IClassFactory) DDCF_Vtbl =
421 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
422 DDCF_QueryInterface,
423 DDCF_AddRef,
424 DDCF_Release,
425 DDCF_CreateInstance,
426 DDCF_LockServer
428 static IClassFactoryImpl DDRAW_CF = {&DDCF_Vtbl, 1 };
430 /*******************************************************************************
431 * DllGetClassObject [DDRAW.13]
432 * Retrieves class object from a DLL object
434 * NOTES
435 * Docs say returns STDAPI
437 * PARAMS
438 * rclsid [I] CLSID for the class object
439 * riid [I] Reference to identifier of interface for class object
440 * ppv [O] Address of variable to receive interface pointer for riid
442 * RETURNS
443 * Success: S_OK
444 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
445 * E_UNEXPECTED
447 DWORD WINAPI DDRAW_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
449 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
450 if ( IsEqualGUID( &IID_IClassFactory, riid ) ) {
451 *ppv = (LPVOID)&DDRAW_CF;
452 IClassFactory_AddRef((IClassFactory*)*ppv);
453 return S_OK;
455 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
456 return CLASS_E_CLASSNOTAVAILABLE;
460 /*******************************************************************************
461 * DllCanUnloadNow [DDRAW.12] Determines whether the DLL is in use.
463 * RETURNS
464 * Success: S_OK
465 * Failure: S_FALSE
467 DWORD WINAPI DDRAW_DllCanUnloadNow(void) {
468 FIXME("(void): stub\n");
469 return S_FALSE;