ddraw: Catch access violations when calling DirectDrawEnumerateProc.
[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  * Copyright 2000-2001 TransGaming Technologies Inc.
6  *
7  * This file contains the (internal) driver registration functions,
8  * driver enumeration APIs and DirectDraw creation functions.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #define GLPRIVATE_NO_REDEFINE
26
27 #include "config.h"
28 #include "wine/port.h"
29
30 #include <assert.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <stdlib.h>
34
35 #define COBJMACROS
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winerror.h"
41 #include "wingdi.h"
42 #include "wine/exception.h"
43 #include "excpt.h"
44
45 #include "ddraw.h"
46 #include "d3d.h"
47
48 /* This for all the enumeration and creation of D3D-related objects */
49 #include "ddraw_private.h"
50 #include "wine/debug.h"
51 #include "wine/library.h"
52
53 #include "gl_private.h"
54
55 #undef GLPRIVATE_NO_REDEFINE
56
57 #define MAX_DDRAW_DRIVERS 3
58 static const ddraw_driver* DDRAW_drivers[MAX_DDRAW_DRIVERS];
59 static int DDRAW_num_drivers; /* = 0 */
60 static int DDRAW_default_driver;
61
62 void (*wine_tsx11_lock_ptr)(void) = NULL;
63 void (*wine_tsx11_unlock_ptr)(void) = NULL;
64
65 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
66
67 /* filter for page-fault exceptions */
68 static WINE_EXCEPTION_FILTER(page_fault)
69 {
70     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
71         return EXCEPTION_EXECUTE_HANDLER;
72     return EXCEPTION_CONTINUE_SEARCH;
73 }
74
75 /**********************************************************************/
76
77 typedef struct {
78     LPVOID lpCallback;
79     LPVOID lpContext;
80 } DirectDrawEnumerateProcData;
81
82 BOOL opengl_initialized = 0;
83
84 #ifdef HAVE_OPENGL
85
86 #include "opengl_private.h"
87
88 static void *gl_handle = NULL;
89
90 #define GL_API_FUNCTION(f) typeof(f) * p##f;
91 #include "gl_api.h"
92 #undef GL_API_FUNCTION
93
94 #ifndef SONAME_LIBGL
95 #define SONAME_LIBGL "libGL.so"
96 #endif
97
98 static BOOL DDRAW_bind_to_opengl( void )
99 {
100     const char *glname = SONAME_LIBGL;
101
102     gl_handle = wine_dlopen(glname, RTLD_NOW, NULL, 0);
103     if (!gl_handle) {
104         WARN("Wine cannot find the OpenGL graphics library (%s).\n",glname);
105         return FALSE;
106     }
107
108 #define GL_API_FUNCTION(f)  \
109     if((p##f = wine_dlsym(gl_handle, #f, NULL, 0)) == NULL) \
110     { \
111         WARN("Can't find symbol %s\n", #f); \
112         goto sym_not_found; \
113     }
114 #include "gl_api.h"
115 #undef GL_API_FUNCTION
116
117     /* And now calls the function to initialize the various fields for the rendering devices */
118     return d3ddevice_init_at_startup(gl_handle);
119     
120 sym_not_found:
121     WARN("Wine cannot find certain functions that it needs inside the OpenGL\n"
122          "graphics library.  To enable Wine to use OpenGL please upgrade\n"
123          "your OpenGL libraries\n");
124     wine_dlclose(gl_handle, NULL, 0);
125     gl_handle = NULL;
126     return FALSE;
127 }
128
129 #endif /* HAVE_OPENGL */
130
131 BOOL s3tc_initialized = 0;
132
133 static void *s3tc_handle = NULL;
134
135 FUNC_FETCH_2D_TEXEL_RGBA_DXT1 fetch_2d_texel_rgba_dxt1;
136 FUNC_FETCH_2D_TEXEL_RGBA_DXT3 fetch_2d_texel_rgba_dxt3;
137 FUNC_FETCH_2D_TEXEL_RGBA_DXT5 fetch_2d_texel_rgba_dxt5;
138
139 #ifndef SONAME_LIBTXC_DXTN
140 #define SONAME_LIBTXC_DXTN "libtxc_dxtn.so"
141 #endif
142
143 static BOOL DDRAW_bind_to_s3tc( void )
144 {
145     const char * const s3tcname = SONAME_LIBTXC_DXTN;
146
147     s3tc_handle = wine_dlopen(s3tcname, RTLD_NOW, NULL, 0);
148     if (!s3tc_handle) {
149         TRACE("No S3TC software decompression library seems to be present (%s).\n",s3tcname);
150         return FALSE;
151     }
152     TRACE("Found S3TC software decompression library (%s).\n",s3tcname);
153
154 #define API_FUNCTION(f)  \
155     if((f = wine_dlsym(s3tc_handle, #f, NULL, 0)) == NULL) \
156     { \
157         WARN("Can't find symbol %s\n", #f); \
158         goto sym_not_found; \
159     }
160     API_FUNCTION(fetch_2d_texel_rgba_dxt1);
161     API_FUNCTION(fetch_2d_texel_rgba_dxt3);
162     API_FUNCTION(fetch_2d_texel_rgba_dxt5);
163 #undef API_FUNCTION
164
165     return TRUE;
166     
167 sym_not_found:
168     WARN("Wine cannot find functions that are necessary for S3TC software decompression\n");
169     wine_dlclose(s3tc_handle, NULL, 0);
170     s3tc_handle = NULL;
171     return FALSE;
172 }
173
174 /*******************************************************************************
175  * DirectDrawEnumerateExA (DDRAW.@)
176  *
177  * Enumerates all DirectDraw devices installed on the system.
178  *
179  * PARAMS
180  *  lpCallback [I] DDEnumCallbackEx function to be called with a description of 
181  *                 each enumerated HAL.
182  *  lpContext  [I] application-defined value to be passed to the callback.
183  *  dwFlags    [I] Specifies the enumeration scope. see msdn.
184  *
185  * RETURNS
186  *  Success: DD_OK.
187  *  Failure: DDERR_INVALIDPARAMS
188  */
189 HRESULT WINAPI DirectDrawEnumerateExA(
190     LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags)
191 {
192     int i;
193     BOOL stop = FALSE;
194     TRACE("(%p,%p, %08lx)\n", lpCallback, lpContext, dwFlags);
195
196     if (TRACE_ON(ddraw)) {
197         TRACE("  Flags : ");
198         if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES)
199             TRACE("DDENUM_ATTACHEDSECONDARYDEVICES ");
200         if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES)
201             TRACE("DDENUM_DETACHEDSECONDARYDEVICES ");
202         if (dwFlags & DDENUM_NONDISPLAYDEVICES)
203             TRACE("DDENUM_NONDISPLAYDEVICES ");
204         TRACE("\n");
205     }
206
207     for (i=0; i<DDRAW_num_drivers; i++)
208     {
209         TRACE("Enumerating %s/%s interface\n",
210               DDRAW_drivers[i]->info->szDriver,
211               DDRAW_drivers[i]->info->szDescription);
212
213         /* We have to pass NULL from the primary display device.
214          * RoadRage chapter 6's enumeration routine expects it. */
215         __TRY
216         {
217             if (!lpCallback((DDRAW_default_driver == i) ? NULL
218                             :(LPGUID)&DDRAW_drivers[i]->info->guidDeviceIdentifier,
219                             (LPSTR)DDRAW_drivers[i]->info->szDescription,
220                             (LPSTR)DDRAW_drivers[i]->info->szDriver,
221                             lpContext, 0))
222                 stop = TRUE;
223         }
224         __EXCEPT(page_fault)
225         {
226             return E_INVALIDARG;
227         }
228         __ENDTRY
229         if (stop) return DD_OK;
230     }
231
232     /* Unsupported flags */
233     if (dwFlags & DDENUM_NONDISPLAYDEVICES) {
234         FIXME("no non-display devices supported.\n");
235     }
236     if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES) {
237         FIXME("no detached secondary devices supported.\n");
238     }
239
240     return DD_OK;
241 }
242
243 /*******************************************************************************
244  * DirectDrawEnumerateExW (DDRAW.@)
245  */
246
247 static BOOL CALLBACK DirectDrawEnumerateExProcW(
248     GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName,
249     LPVOID lpContext, HMONITOR hm)
250 {
251     INT len;
252     BOOL bResult;
253     LPWSTR lpDriverDescriptionW, lpDriverNameW;
254     DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
255
256     len = MultiByteToWideChar( CP_ACP, 0, lpDriverDescription, -1, NULL, 0 );
257     lpDriverDescriptionW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
258     MultiByteToWideChar( CP_ACP, 0, lpDriverDescription, -1, lpDriverDescriptionW, len );
259
260     len = MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, NULL, 0 );
261     lpDriverNameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
262     MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, lpDriverNameW, len );
263
264     bResult = (*(LPDDENUMCALLBACKEXW *) pEPD->lpCallback)(lpGUID, lpDriverDescriptionW,
265                                                           lpDriverNameW, pEPD->lpContext, hm);
266
267     HeapFree(GetProcessHeap(), 0, lpDriverDescriptionW);
268     HeapFree(GetProcessHeap(), 0, lpDriverNameW);
269     return bResult;
270 }
271
272 HRESULT WINAPI DirectDrawEnumerateExW(
273   LPDDENUMCALLBACKEXW lpCallback, LPVOID lpContext, DWORD dwFlags)
274 {
275     DirectDrawEnumerateProcData epd;
276     epd.lpCallback = (LPVOID) lpCallback;
277     epd.lpContext = lpContext;
278
279     return DirectDrawEnumerateExA(DirectDrawEnumerateExProcW, (LPVOID) &epd, 0);
280 }
281
282 /***********************************************************************
283  *              DirectDrawEnumerateA (DDRAW.@)
284  */
285
286 static BOOL CALLBACK DirectDrawEnumerateProcA(
287         GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName,
288         LPVOID lpContext, HMONITOR hm)
289 {
290     DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
291
292     return ((LPDDENUMCALLBACKA) pEPD->lpCallback)(
293         lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext);
294 }
295
296 HRESULT WINAPI DirectDrawEnumerateA(
297   LPDDENUMCALLBACKA lpCallback, LPVOID lpContext)
298 {
299     DirectDrawEnumerateProcData epd;
300     epd.lpCallback = (LPVOID) lpCallback;
301     epd.lpContext = lpContext;
302
303     return DirectDrawEnumerateExA(DirectDrawEnumerateProcA, (LPVOID) &epd, 0);
304 }
305
306 /***********************************************************************
307  *              DirectDrawEnumerateW (DDRAW.@)
308  */
309
310 static BOOL WINAPI DirectDrawEnumerateProcW(
311   GUID *lpGUID, LPWSTR lpDriverDescription, LPWSTR lpDriverName,
312   LPVOID lpContext, HMONITOR hm)
313 {
314     DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
315
316     return ((LPDDENUMCALLBACKW) pEPD->lpCallback)(
317         lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext);
318 }
319
320 HRESULT WINAPI DirectDrawEnumerateW(
321   LPDDENUMCALLBACKW lpCallback, LPVOID lpContext)
322 {
323     DirectDrawEnumerateProcData epd;
324     epd.lpCallback = (LPVOID) lpCallback;
325     epd.lpContext = lpContext;
326
327     return DirectDrawEnumerateExW(DirectDrawEnumerateProcW, (LPVOID) &epd, 0);
328 }
329
330 /***********************************************************************
331  *              DirectDrawCreate (DDRAW.@)
332  */
333
334 const ddraw_driver* DDRAW_FindDriver(const GUID* pGUID)
335 {
336     static const GUID zeroGUID; /* gets zero-inited */
337
338     TRACE("(%s)\n", pGUID ? debugstr_guid(pGUID) : "(null)");
339
340     if (DDRAW_num_drivers == 0) return NULL;
341
342     if (pGUID == (LPGUID)DDCREATE_EMULATIONONLY
343         || pGUID == (LPGUID)DDCREATE_HARDWAREONLY)
344         pGUID = NULL;
345
346     if (pGUID == NULL || memcmp(pGUID, &zeroGUID, sizeof(GUID)) == 0)
347     {
348         /* Use the default driver. */
349         return DDRAW_drivers[DDRAW_default_driver];
350     }
351     else
352     {
353         /* Look for a matching GUID. */
354
355         int i;
356         for (i=0; i < DDRAW_num_drivers; i++)
357         {
358             if (IsEqualGUID(pGUID,
359                             &DDRAW_drivers[i]->info->guidDeviceIdentifier))
360                 break;
361         }
362
363         if (i < DDRAW_num_drivers)
364         {
365             return DDRAW_drivers[i];
366         }
367         else
368         {
369             ERR("(%s): did not recognize requested GUID.\n",debugstr_guid(pGUID));
370             return NULL;
371         }
372     }
373 }
374
375 static HRESULT DDRAW_Create(
376         LPGUID lpGUID, LPVOID *lplpDD, LPUNKNOWN pUnkOuter, REFIID iid, BOOL ex
377 ) {
378     const ddraw_driver* driver;
379     LPDIRECTDRAW7 pDD;
380     HRESULT hr;
381
382     TRACE("(%s,%p,%p,%d)\n", debugstr_guid(lpGUID), lplpDD, pUnkOuter, ex);
383
384     if (DDRAW_num_drivers == 0)
385     {
386         WARN("no DirectDraw drivers registered\n");
387         return DDERR_INVALIDDIRECTDRAWGUID;
388     }
389
390     if (lpGUID == (LPGUID)DDCREATE_EMULATIONONLY
391         || lpGUID == (LPGUID)DDCREATE_HARDWAREONLY)
392         lpGUID = NULL;
393
394     if (pUnkOuter != NULL)
395         return DDERR_INVALIDPARAMS; /* CLASS_E_NOAGGREGATION? */
396
397     driver = DDRAW_FindDriver(lpGUID);
398     if (driver == NULL) return DDERR_INVALIDDIRECTDRAWGUID;
399
400     hr = driver->create(lpGUID, &pDD, pUnkOuter, ex);
401     if (FAILED(hr)) return hr;
402
403     hr = IDirectDraw7_QueryInterface(pDD, iid, lplpDD);
404     IDirectDraw7_Release(pDD);
405     return hr;
406 }
407
408 /***********************************************************************
409  *              DirectDrawCreate (DDRAW.@)
410  *
411  * Only creates legacy IDirectDraw interfaces.
412  * Cannot create IDirectDraw7 interfaces.
413  * In theory.
414  */
415 HRESULT WINAPI DirectDrawCreate(
416         LPGUID lpGUID, LPDIRECTDRAW* lplpDD, LPUNKNOWN pUnkOuter
417 ) {
418     TRACE("(%s,%p,%p)\n", debugstr_guid(lpGUID), lplpDD, pUnkOuter);
419     return DDRAW_Create(lpGUID, (LPVOID*) lplpDD, pUnkOuter, &IID_IDirectDraw, FALSE);
420 }
421
422 /***********************************************************************
423  *              DirectDrawCreateEx (DDRAW.@)
424  *
425  * Only creates new IDirectDraw7 interfaces.
426  * Supposed to fail if legacy interfaces are requested.
427  * In theory.
428  */
429 HRESULT WINAPI DirectDrawCreateEx(
430         LPGUID lpGUID, LPVOID* lplpDD, REFIID iid, LPUNKNOWN pUnkOuter
431 ) {
432     TRACE("(%s,%p,%s,%p)\n", debugstr_guid(lpGUID), lplpDD, debugstr_guid(iid), pUnkOuter);
433
434     if (!IsEqualGUID(iid, &IID_IDirectDraw7))
435         return DDERR_INVALIDPARAMS;
436
437     return DDRAW_Create(lpGUID, lplpDD, pUnkOuter, iid, TRUE);
438 }
439
440 extern HRESULT Uninit_DirectDraw_Create(const GUID*, LPDIRECTDRAW7*,
441                                         LPUNKNOWN, BOOL);
442
443 /* This is for the class factory. */
444 static HRESULT DDRAW_CreateDirectDraw(IUnknown* pUnkOuter, REFIID iid,
445                                       LPVOID* ppObj)
446 {
447     LPDIRECTDRAW7 pDD;
448     HRESULT hr;
449     BOOL ex;
450
451     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppObj);
452     
453     /* This is a mighty hack :-) */
454     if (IsEqualGUID(iid, &IID_IDirectDraw7))
455         ex = TRUE;
456     else
457         ex = FALSE;
458     
459     hr = Uninit_DirectDraw_Create(NULL, &pDD, pUnkOuter, ex);
460     if (FAILED(hr)) return hr;
461
462     hr = IDirectDraw7_QueryInterface(pDD, iid, ppObj);
463     IDirectDraw_Release(pDD);
464     return hr;
465 }
466
467 /******************************************************************************
468  * DirectDraw ClassFactory
469  */
470 typedef struct {
471     ICOM_VFIELD_MULTI(IClassFactory);
472
473     LONG ref;
474     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID iid,
475                                  LPVOID *ppObj);
476 } IClassFactoryImpl;
477
478 struct object_creation_info
479 {
480     const CLSID *clsid;
481     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID riid,
482                                  LPVOID *ppObj);
483 };
484
485 /* There should be more, but these are the only ones listed in the header
486  * file. */
487 extern HRESULT DDRAW_CreateDirectDrawClipper(IUnknown *pUnkOuter, REFIID riid,
488                                              LPVOID *ppObj);
489
490 static const struct object_creation_info object_creation[] =
491 {
492     { &CLSID_DirectDraw,        DDRAW_CreateDirectDraw },
493     { &CLSID_DirectDraw7,       DDRAW_CreateDirectDraw },
494     { &CLSID_DirectDrawClipper, DDRAW_CreateDirectDrawClipper }
495 };
496
497 static HRESULT WINAPI
498 DDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
499 {
500     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
501
502     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj);
503     
504     if (IsEqualGUID(riid, &IID_IUnknown)
505         || IsEqualGUID(riid, &IID_IClassFactory))
506     {
507         IClassFactory_AddRef(iface);
508         *ppobj = This;
509         return S_OK;
510     }
511
512     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
513     return E_NOINTERFACE;
514 }
515
516 static ULONG WINAPI DDCF_AddRef(LPCLASSFACTORY iface)
517 {
518     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
519     ULONG ref = InterlockedIncrement(&This->ref);
520
521     TRACE("(%p)->() incrementing from %ld.\n", This, ref - 1);
522     
523     return ref;
524 }
525
526 static ULONG WINAPI DDCF_Release(LPCLASSFACTORY iface)
527 {
528     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
529     ULONG ref = InterlockedDecrement(&This->ref);
530     TRACE("(%p)->() decrementing from %ld.\n", This, ref+1);
531
532     if (ref == 0)
533         HeapFree(GetProcessHeap(), 0, This);
534
535     return ref;
536 }
537
538
539 static HRESULT WINAPI DDCF_CreateInstance(
540         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
541 )
542 {
543     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
544
545     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
546
547     return This->pfnCreateInstance(pOuter, riid, ppobj);
548 }
549
550 static HRESULT WINAPI DDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
551 {
552     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
553     FIXME("(%p)->(%d),stub!\n",This,dolock);
554     return S_OK;
555 }
556
557 static const IClassFactoryVtbl DDCF_Vtbl =
558 {
559     DDCF_QueryInterface,
560     DDCF_AddRef,
561     DDCF_Release,
562     DDCF_CreateInstance,
563     DDCF_LockServer
564 };
565
566 /*******************************************************************************
567  * DllGetClassObject [DDRAW.@]
568  * Retrieves class object from a DLL object
569  *
570  * NOTES
571  *    Docs say returns STDAPI
572  *
573  * PARAMS
574  *    rclsid [I] CLSID for the class object
575  *    riid   [I] Reference to identifier of interface for class object
576  *    ppv    [O] Address of variable to receive interface pointer for riid
577  *
578  * RETURNS
579  *    Success: S_OK
580  *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
581  *             E_UNEXPECTED
582  */
583 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
584 {
585     unsigned int i;
586     IClassFactoryImpl *factory;
587
588     TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
589
590     if ( !IsEqualGUID( &IID_IClassFactory, riid )
591          && ! IsEqualGUID( &IID_IUnknown, riid) )
592         return E_NOINTERFACE;
593
594     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
595     {
596         if (IsEqualGUID(object_creation[i].clsid, rclsid))
597             break;
598     }
599
600     if (i == sizeof(object_creation)/sizeof(object_creation[0]))
601     {
602         FIXME("%s: no class found.\n", debugstr_guid(rclsid));
603         return CLASS_E_CLASSNOTAVAILABLE;
604     }
605
606     factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
607     if (factory == NULL) return E_OUTOFMEMORY;
608
609     ICOM_INIT_INTERFACE(factory, IClassFactory, DDCF_Vtbl);
610     factory->ref = 1;
611
612     factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
613
614     *ppv = ICOM_INTERFACE(factory, IClassFactory);
615     return S_OK;
616 }
617
618
619 /*******************************************************************************
620  * DllCanUnloadNow [DDRAW.@]  Determines whether the DLL is in use.
621  *
622  * RETURNS
623  *    Success: S_OK
624  *    Failure: S_FALSE
625  */
626 HRESULT WINAPI DllCanUnloadNow(void)
627 {
628     FIXME("(void): stub\n");
629     return S_FALSE;
630 }
631
632 /******************************************************************************
633  * Initialisation
634  */
635
636 /* Choose which driver is considered the primary display driver. It will
637  * be created when we get a NULL guid for the DirectDrawCreate(Ex). */
638 static int DDRAW_ChooseDefaultDriver(void)
639 {
640     int i;
641     int best = 0;
642     int best_score = 0;
643
644     assert(DDRAW_num_drivers > 0);
645
646     /* This algorithm is really stupid. */
647     for (i=0; i < DDRAW_num_drivers; i++)
648     {
649         if (DDRAW_drivers[i]->preference > best_score)
650         {
651             best_score = DDRAW_drivers[i]->preference;
652             best = i;
653         }
654     }
655
656     assert(best_score > 0);
657
658     return best;
659 }
660
661 /***********************************************************************
662  *              DllMain (DDRAW.0)
663  */
664 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
665 {
666     /* If we were sufficiently cool, DDraw drivers would just be COM
667      * objects, registered with a particular component category. */
668
669     DDRAW_HAL_Init(hInstDLL, fdwReason, lpv);
670     DDRAW_User_Init(hInstDLL, fdwReason, lpv);
671
672     if (fdwReason == DLL_PROCESS_ATTACH)
673     {
674         HMODULE mod;
675
676         DisableThreadLibraryCalls(hInstDLL);
677
678         mod = GetModuleHandleA( "winex11.drv" );
679         if (mod)
680         {
681             wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
682             wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
683         }
684 #ifdef HAVE_OPENGL
685         opengl_initialized = DDRAW_bind_to_opengl();
686 #endif /* HAVE_OPENGL */
687         s3tc_initialized = DDRAW_bind_to_s3tc();
688     }
689
690     if (DDRAW_num_drivers > 0)
691         DDRAW_default_driver = DDRAW_ChooseDefaultDriver();
692
693     return TRUE;
694 }
695
696 /* Register a direct draw driver. This should be called from your init
697  * function. (That's why there is no locking: your init func is called from
698  * our DllInit, which is serialised.) */
699 void DDRAW_register_driver(const ddraw_driver *driver)
700 {
701     int i;
702
703     for (i = 0; i < DDRAW_num_drivers; i++)
704     {
705         if (DDRAW_drivers[i] == driver)
706         {
707             ERR("Driver reregistering %p\n", driver);
708             return;
709         }
710     }
711
712     if (DDRAW_num_drivers == sizeof(DDRAW_drivers)/sizeof(DDRAW_drivers[0]))
713     {
714         ERR("too many DDRAW drivers\n");
715         return;
716     }
717
718     DDRAW_drivers[DDRAW_num_drivers++] = driver;
719 }
720
721 /* This totally doesn't belong here. */
722 LONG DDRAW_width_bpp_to_pitch(DWORD width, DWORD bpp)
723 {
724     LONG pitch;
725
726     assert(bpp != 0); /* keeps happening... */
727
728     if (bpp == 15) bpp = 16;
729     pitch = width * (bpp / 8);
730     return pitch + (8 - (pitch % 8)) % 8;
731 }