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