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