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