gdiplus: Implement GetDC for metafiles.
[wine] / dlls / ddraw / main.c
1 /*        DirectDraw Base Functions
2  *
3  * Copyright 1997-1999 Marcus Meissner
4  * Copyright 1998 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  * Copyright 2006 Stefan Dösinger
7  * Copyright 2008 Denver Gingerich
8  *
9  * This file contains the (internal) driver registration functions,
10  * driver enumeration APIs and DirectDraw creation functions.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26
27 #include "config.h"
28 #include "wine/port.h"
29
30 #define DDRAW_INIT_GUID
31 #include "ddraw_private.h"
32 #include "rpcproxy.h"
33
34 #include "wine/exception.h"
35 #include "winreg.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
38
39 /* The configured default surface */
40 WINED3DSURFTYPE DefaultSurfaceType = SURFACE_UNKNOWN;
41
42 /* DDraw list and critical section */
43 static struct list global_ddraw_list = LIST_INIT(global_ddraw_list);
44
45 static CRITICAL_SECTION_DEBUG ddraw_cs_debug =
46 {
47     0, 0, &ddraw_cs,
48     { &ddraw_cs_debug.ProcessLocksList,
49     &ddraw_cs_debug.ProcessLocksList },
50     0, 0, { (DWORD_PTR)(__FILE__ ": ddraw_cs") }
51 };
52 CRITICAL_SECTION ddraw_cs = { &ddraw_cs_debug, -1, 0, 0, 0, 0 };
53
54 static HINSTANCE instance;
55
56 /* value of ForceRefreshRate */
57 DWORD force_refresh_rate = 0;
58
59 /* Handle table functions */
60 BOOL ddraw_handle_table_init(struct ddraw_handle_table *t, UINT initial_size)
61 {
62     t->entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, initial_size * sizeof(*t->entries));
63     if (!t->entries)
64     {
65         ERR("Failed to allocate handle table memory.\n");
66         return FALSE;
67     }
68     t->free_entries = NULL;
69     t->table_size = initial_size;
70     t->entry_count = 0;
71
72     return TRUE;
73 }
74
75 void ddraw_handle_table_destroy(struct ddraw_handle_table *t)
76 {
77     HeapFree(GetProcessHeap(), 0, t->entries);
78     memset(t, 0, sizeof(*t));
79 }
80
81 DWORD ddraw_allocate_handle(struct ddraw_handle_table *t, void *object, enum ddraw_handle_type type)
82 {
83     struct ddraw_handle_entry *entry;
84
85     if (t->free_entries)
86     {
87         DWORD idx = t->free_entries - t->entries;
88         /* Use a free handle */
89         entry = t->free_entries;
90         if (entry->type != DDRAW_HANDLE_FREE)
91         {
92             ERR("Handle %#x (%p) is in the free list, but has type %#x.\n", idx, entry->object, entry->type);
93             return DDRAW_INVALID_HANDLE;
94         }
95         t->free_entries = entry->object;
96         entry->object = object;
97         entry->type = type;
98
99         return idx;
100     }
101
102     if (!(t->entry_count < t->table_size))
103     {
104         /* Grow the table */
105         UINT new_size = t->table_size + (t->table_size >> 1);
106         struct ddraw_handle_entry *new_entries = HeapReAlloc(GetProcessHeap(),
107                 0, t->entries, new_size * sizeof(*t->entries));
108         if (!new_entries)
109         {
110             ERR("Failed to grow the handle table.\n");
111             return DDRAW_INVALID_HANDLE;
112         }
113         t->entries = new_entries;
114         t->table_size = new_size;
115     }
116
117     entry = &t->entries[t->entry_count];
118     entry->object = object;
119     entry->type = type;
120
121     return t->entry_count++;
122 }
123
124 void *ddraw_free_handle(struct ddraw_handle_table *t, DWORD handle, enum ddraw_handle_type type)
125 {
126     struct ddraw_handle_entry *entry;
127     void *object;
128
129     if (handle == DDRAW_INVALID_HANDLE || handle >= t->entry_count)
130     {
131         WARN("Invalid handle %#x passed.\n", handle);
132         return NULL;
133     }
134
135     entry = &t->entries[handle];
136     if (entry->type != type)
137     {
138         WARN("Handle %#x (%p) is not of type %#x.\n", handle, entry->object, type);
139         return NULL;
140     }
141
142     object = entry->object;
143     entry->object = t->free_entries;
144     entry->type = DDRAW_HANDLE_FREE;
145     t->free_entries = entry;
146
147     return object;
148 }
149
150 void *ddraw_get_object(struct ddraw_handle_table *t, DWORD handle, enum ddraw_handle_type type)
151 {
152     struct ddraw_handle_entry *entry;
153
154     if (handle == DDRAW_INVALID_HANDLE || handle >= t->entry_count)
155     {
156         WARN("Invalid handle %#x passed.\n", handle);
157         return NULL;
158     }
159
160     entry = &t->entries[handle];
161     if (entry->type != type)
162     {
163         WARN("Handle %#x (%p) is not of type %#x.\n", handle, entry->object, type);
164         return NULL;
165     }
166
167     return entry->object;
168 }
169
170 /***********************************************************************
171  *
172  * Helper function for DirectDrawCreate and friends
173  * Creates a new DDraw interface with the given REFIID
174  *
175  * Interfaces that can be created:
176  *  IDirectDraw, IDirectDraw2, IDirectDraw4, IDirectDraw7
177  *  IDirect3D, IDirect3D2, IDirect3D3, IDirect3D7. (Does Windows return
178  *  IDirect3D interfaces?)
179  *
180  * Arguments:
181  *  guid: ID of the requested driver, NULL for the default driver.
182  *        The GUID can be queried with DirectDrawEnumerate(Ex)A/W
183  *  DD: Used to return the pointer to the created object
184  *  UnkOuter: For aggregation, which is unsupported. Must be NULL
185  *  iid: requested version ID.
186  *
187  * Returns:
188  *  DD_OK if the Interface was created successfully
189  *  CLASS_E_NOAGGREGATION if UnkOuter is not NULL
190  *  E_OUTOFMEMORY if some allocation failed
191  *
192  ***********************************************************************/
193 static HRESULT
194 DDRAW_Create(const GUID *guid,
195              void **DD,
196              IUnknown *UnkOuter,
197              REFIID iid)
198 {
199     WINED3DDEVTYPE devicetype;
200     IDirectDrawImpl *This;
201     HRESULT hr;
202
203     TRACE("driver_guid %s, ddraw %p, outer_unknown %p, interface_iid %s.\n",
204             debugstr_guid(guid), DD, UnkOuter, debugstr_guid(iid));
205
206     *DD = NULL;
207
208     /* We don't care about this guids. Well, there's no special guid anyway
209      * OK, we could
210      */
211     if (guid == (GUID *) DDCREATE_EMULATIONONLY)
212     {
213         /* Use the reference device id. This doesn't actually change anything,
214          * WineD3D always uses OpenGL for D3D rendering. One could make it request
215          * indirect rendering
216          */
217         devicetype = WINED3DDEVTYPE_REF;
218     }
219     else if(guid == (GUID *) DDCREATE_HARDWAREONLY)
220     {
221         devicetype = WINED3DDEVTYPE_HAL;
222     }
223     else
224     {
225         devicetype = 0;
226     }
227
228     /* DDraw doesn't support aggregation, according to msdn */
229     if (UnkOuter != NULL)
230         return CLASS_E_NOAGGREGATION;
231
232     /* DirectDraw creation comes here */
233     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectDrawImpl));
234     if(!This)
235     {
236         ERR("Out of memory when creating DirectDraw\n");
237         return E_OUTOFMEMORY;
238     }
239
240     hr = ddraw_init(This, devicetype);
241     if (FAILED(hr))
242     {
243         WARN("Failed to initialize ddraw object, hr %#x.\n", hr);
244         HeapFree(GetProcessHeap(), 0, This);
245         return hr;
246     }
247
248     hr = IDirectDraw7_QueryInterface(&This->IDirectDraw7_iface, iid, DD);
249     IDirectDraw7_Release(&This->IDirectDraw7_iface);
250     if (SUCCEEDED(hr)) list_add_head(&global_ddraw_list, &This->ddraw_list_entry);
251     else WARN("Failed to query interface %s from ddraw object %p.\n", debugstr_guid(iid), This);
252
253     return hr;
254 }
255
256 /***********************************************************************
257  * DirectDrawCreate (DDRAW.@)
258  *
259  * Creates legacy DirectDraw Interfaces. Can't create IDirectDraw7
260  * interfaces in theory
261  *
262  * Arguments, return values: See DDRAW_Create
263  *
264  ***********************************************************************/
265 HRESULT WINAPI DECLSPEC_HOTPATCH
266 DirectDrawCreate(GUID *GUID,
267                  LPDIRECTDRAW *DD,
268                  IUnknown *UnkOuter)
269 {
270     HRESULT hr;
271
272     TRACE("driver_guid %s, ddraw %p, outer_unknown %p.\n",
273             debugstr_guid(GUID), DD, UnkOuter);
274
275     EnterCriticalSection(&ddraw_cs);
276     hr = DDRAW_Create(GUID, (void **) DD, UnkOuter, &IID_IDirectDraw);
277     LeaveCriticalSection(&ddraw_cs);
278     return hr;
279 }
280
281 /***********************************************************************
282  * DirectDrawCreateEx (DDRAW.@)
283  *
284  * Only creates new IDirectDraw7 interfaces, supposed to fail if legacy
285  * interfaces are requested.
286  *
287  * Arguments, return values: See DDRAW_Create
288  *
289  ***********************************************************************/
290 HRESULT WINAPI DECLSPEC_HOTPATCH
291 DirectDrawCreateEx(GUID *GUID,
292                    LPVOID *DD,
293                    REFIID iid,
294                    IUnknown *UnkOuter)
295 {
296     HRESULT hr;
297
298     TRACE("driver_guid %s, ddraw %p, interface_iid %s, outer_unknown %p.\n",
299             debugstr_guid(GUID), DD, debugstr_guid(iid), UnkOuter);
300
301     if (!IsEqualGUID(iid, &IID_IDirectDraw7))
302         return DDERR_INVALIDPARAMS;
303
304     EnterCriticalSection(&ddraw_cs);
305     hr = DDRAW_Create(GUID, DD, UnkOuter, iid);
306     LeaveCriticalSection(&ddraw_cs);
307     return hr;
308 }
309
310 /***********************************************************************
311  * DirectDrawEnumerateA (DDRAW.@)
312  *
313  * Enumerates legacy ddraw drivers, ascii version. We only have one
314  * driver, which relays to WineD3D. If we were sufficiently cool,
315  * we could offer various interfaces, which use a different default surface
316  * implementation, but I think it's better to offer this choice in
317  * winecfg, because some apps use the default driver, so we would need
318  * a winecfg option anyway, and there shouldn't be 2 ways to set one setting
319  *
320  * Arguments:
321  *  Callback: Callback function from the app
322  *  Context: Argument to the call back.
323  *
324  * Returns:
325  *  DD_OK on success
326  *  E_INVALIDARG if the Callback caused a page fault
327  *
328  *
329  ***********************************************************************/
330 HRESULT WINAPI DirectDrawEnumerateA(LPDDENUMCALLBACKA Callback, void *Context)
331 {
332     TRACE("callback %p, context %p.\n", Callback, Context);
333
334     TRACE(" Enumerating default DirectDraw HAL interface\n");
335     /* We only have one driver */
336     __TRY
337     {
338         static CHAR driver_desc[] = "DirectDraw HAL",
339         driver_name[] = "display";
340
341         Callback(NULL, driver_desc, driver_name, Context);
342     }
343     __EXCEPT_PAGE_FAULT
344     {
345         return DDERR_INVALIDPARAMS;
346     }
347     __ENDTRY
348
349     TRACE(" End of enumeration\n");
350     return DD_OK;
351 }
352
353 /***********************************************************************
354  * DirectDrawEnumerateExA (DDRAW.@)
355  *
356  * Enumerates DirectDraw7 drivers, ascii version. See
357  * the comments above DirectDrawEnumerateA for more details.
358  *
359  * The Flag member is not supported right now.
360  *
361  ***********************************************************************/
362 HRESULT WINAPI DirectDrawEnumerateExA(LPDDENUMCALLBACKEXA Callback, void *Context, DWORD Flags)
363 {
364     TRACE("callback %p, context %p, flags %#x.\n", Callback, Context, Flags);
365
366     if (Flags & ~(DDENUM_ATTACHEDSECONDARYDEVICES |
367                   DDENUM_DETACHEDSECONDARYDEVICES |
368                   DDENUM_NONDISPLAYDEVICES))
369         return DDERR_INVALIDPARAMS;
370
371     if (Flags)
372         FIXME("flags 0x%08x not handled\n", Flags);
373
374     TRACE("Enumerating default DirectDraw HAL interface\n");
375
376     /* We only have one driver by now */
377     __TRY
378     {
379         static CHAR driver_desc[] = "DirectDraw HAL",
380         driver_name[] = "display";
381
382         /* QuickTime expects the description "DirectDraw HAL" */
383         Callback(NULL, driver_desc, driver_name, Context, 0);
384     }
385     __EXCEPT_PAGE_FAULT
386     {
387         return DDERR_INVALIDPARAMS;
388     }
389     __ENDTRY;
390
391     TRACE("End of enumeration\n");
392     return DD_OK;
393 }
394
395 /***********************************************************************
396  * DirectDrawEnumerateW (DDRAW.@)
397  *
398  * Enumerates legacy drivers, unicode version.
399  * This function is not implemented on Windows.
400  *
401  ***********************************************************************/
402 HRESULT WINAPI DirectDrawEnumerateW(LPDDENUMCALLBACKW callback, void *context)
403 {
404     TRACE("callback %p, context %p.\n", callback, context);
405
406     if (!callback)
407         return DDERR_INVALIDPARAMS;
408     else
409         return DDERR_UNSUPPORTED;
410 }
411
412 /***********************************************************************
413  * DirectDrawEnumerateExW (DDRAW.@)
414  *
415  * Enumerates DirectDraw7 drivers, unicode version.
416  * This function is not implemented on Windows.
417  *
418  ***********************************************************************/
419 HRESULT WINAPI DirectDrawEnumerateExW(LPDDENUMCALLBACKEXW callback, void *context, DWORD flags)
420 {
421     TRACE("callback %p, context %p, flags %#x.\n", callback, context, flags);
422
423     return DDERR_UNSUPPORTED;
424 }
425
426 /***********************************************************************
427  * Classfactory implementation.
428  ***********************************************************************/
429
430 /***********************************************************************
431  * CF_CreateDirectDraw
432  *
433  * DDraw creation function for the class factory
434  *
435  * Params:
436  *  UnkOuter: Set to NULL
437  *  iid: ID of the wanted interface
438  *  obj: Address to pass the interface pointer back
439  *
440  * Returns
441  *  DD_OK / DDERR*, see DDRAW_Create
442  *
443  ***********************************************************************/
444 static HRESULT
445 CF_CreateDirectDraw(IUnknown* UnkOuter, REFIID iid,
446                     void **obj)
447 {
448     HRESULT hr;
449
450     TRACE("outer_unknown %p, riid %s, object %p.\n", UnkOuter, debugstr_guid(iid), obj);
451
452     EnterCriticalSection(&ddraw_cs);
453     hr = DDRAW_Create(NULL, obj, UnkOuter, iid);
454     LeaveCriticalSection(&ddraw_cs);
455     return hr;
456 }
457
458 /***********************************************************************
459  * CF_CreateDirectDraw
460  *
461  * Clipper creation function for the class factory
462  *
463  * Params:
464  *  UnkOuter: Set to NULL
465  *  iid: ID of the wanted interface
466  *  obj: Address to pass the interface pointer back
467  *
468  * Returns
469  *  DD_OK / DDERR*, see DDRAW_Create
470  *
471  ***********************************************************************/
472 static HRESULT
473 CF_CreateDirectDrawClipper(IUnknown* UnkOuter, REFIID riid,
474                               void **obj)
475 {
476     HRESULT hr;
477     IDirectDrawClipper *Clip;
478
479     TRACE("outer_unknown %p, riid %s, object %p.\n", UnkOuter, debugstr_guid(riid), obj);
480
481     EnterCriticalSection(&ddraw_cs);
482     hr = DirectDrawCreateClipper(0, &Clip, UnkOuter);
483     if (hr != DD_OK)
484     {
485         LeaveCriticalSection(&ddraw_cs);
486         return hr;
487     }
488
489     hr = IDirectDrawClipper_QueryInterface(Clip, riid, obj);
490     IDirectDrawClipper_Release(Clip);
491
492     LeaveCriticalSection(&ddraw_cs);
493     return hr;
494 }
495
496 static const struct object_creation_info object_creation[] =
497 {
498     { &CLSID_DirectDraw,        CF_CreateDirectDraw },
499     { &CLSID_DirectDraw7,       CF_CreateDirectDraw },
500     { &CLSID_DirectDrawClipper, CF_CreateDirectDrawClipper }
501 };
502
503
504 /******************************************************************************
505  * DirectDraw ClassFactory implementation
506  ******************************************************************************/
507 typedef struct
508 {
509     IClassFactory IClassFactory_iface;
510
511     LONG ref;
512     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID iid, LPVOID *ppObj);
513 } IClassFactoryImpl;
514
515 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
516 {
517     return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
518 }
519
520 /*******************************************************************************
521  * IDirectDrawClassFactory::QueryInterface
522  *
523  * QueryInterface for the class factory
524  *
525  * PARAMS
526  *    riid   Reference to identifier of queried interface
527  *    ppv    Address to return the interface pointer at
528  *
529  * RETURNS
530  *    Success: S_OK
531  *    Failure: E_NOINTERFACE
532  *
533  *******************************************************************************/
534 static HRESULT WINAPI IDirectDrawClassFactoryImpl_QueryInterface(IClassFactory *iface, REFIID riid,
535         void **obj)
536 {
537     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
538
539     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obj);
540
541     if (IsEqualGUID(riid, &IID_IUnknown)
542         || IsEqualGUID(riid, &IID_IClassFactory))
543     {
544         IClassFactory_AddRef(iface);
545         *obj = This;
546         return S_OK;
547     }
548
549     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),obj);
550     return E_NOINTERFACE;
551 }
552
553 /*******************************************************************************
554  * IDirectDrawClassFactory::AddRef
555  *
556  * AddRef for the class factory
557  *
558  * RETURNS
559  *  The new refcount
560  *
561  *******************************************************************************/
562 static ULONG WINAPI IDirectDrawClassFactoryImpl_AddRef(IClassFactory *iface)
563 {
564     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
565     ULONG ref = InterlockedIncrement(&This->ref);
566
567     TRACE("%p increasing refcount to %u.\n", This, ref);
568
569     return ref;
570 }
571
572 /*******************************************************************************
573  * IDirectDrawClassFactory::Release
574  *
575  * Release for the class factory. If the refcount falls to 0, the object
576  * is destroyed
577  *
578  * RETURNS
579  *  The new refcount
580  *
581  *******************************************************************************/
582 static ULONG WINAPI IDirectDrawClassFactoryImpl_Release(IClassFactory *iface)
583 {
584     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
585     ULONG ref = InterlockedDecrement(&This->ref);
586
587     TRACE("%p decreasing refcount to %u.\n", This, ref);
588
589     if (ref == 0)
590         HeapFree(GetProcessHeap(), 0, This);
591
592     return ref;
593 }
594
595
596 /*******************************************************************************
597  * IDirectDrawClassFactory::CreateInstance
598  *
599  * What is this? Seems to create DirectDraw objects...
600  *
601  * Params
602  *  The usual things???
603  *
604  * RETURNS
605  *  ???
606  *
607  *******************************************************************************/
608 static HRESULT WINAPI IDirectDrawClassFactoryImpl_CreateInstance(IClassFactory *iface,
609         IUnknown *UnkOuter, REFIID riid, void **obj)
610 {
611     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
612
613     TRACE("iface %p, outer_unknown %p, riid %s, object %p.\n",
614             iface, UnkOuter, debugstr_guid(riid), obj);
615
616     return This->pfnCreateInstance(UnkOuter, riid, obj);
617 }
618
619 /*******************************************************************************
620  * IDirectDrawClassFactory::LockServer
621  *
622  * What is this?
623  *
624  * Params
625  *  ???
626  *
627  * RETURNS
628  *  S_OK, because it's a stub
629  *
630  *******************************************************************************/
631 static HRESULT WINAPI IDirectDrawClassFactoryImpl_LockServer(IClassFactory *iface, BOOL dolock)
632 {
633     FIXME("iface %p, dolock %#x stub!\n", iface, dolock);
634
635     return S_OK;
636 }
637
638 /*******************************************************************************
639  * The class factory VTable
640  *******************************************************************************/
641 static const IClassFactoryVtbl IClassFactory_Vtbl =
642 {
643     IDirectDrawClassFactoryImpl_QueryInterface,
644     IDirectDrawClassFactoryImpl_AddRef,
645     IDirectDrawClassFactoryImpl_Release,
646     IDirectDrawClassFactoryImpl_CreateInstance,
647     IDirectDrawClassFactoryImpl_LockServer
648 };
649
650 /*******************************************************************************
651  * DllGetClassObject [DDRAW.@]
652  * Retrieves class object from a DLL object
653  *
654  * NOTES
655  *    Docs say returns STDAPI
656  *
657  * PARAMS
658  *    rclsid [I] CLSID for the class object
659  *    riid   [I] Reference to identifier of interface for class object
660  *    ppv    [O] Address of variable to receive interface pointer for riid
661  *
662  * RETURNS
663  *    Success: S_OK
664  *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
665  *             E_UNEXPECTED
666  */
667 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
668 {
669     unsigned int i;
670     IClassFactoryImpl *factory;
671
672     TRACE("rclsid %s, riid %s, object %p.\n",
673             debugstr_guid(rclsid), debugstr_guid(riid), ppv);
674
675     if (!IsEqualGUID(&IID_IClassFactory, riid)
676             && !IsEqualGUID(&IID_IUnknown, riid))
677         return E_NOINTERFACE;
678
679     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
680     {
681         if (IsEqualGUID(object_creation[i].clsid, rclsid))
682             break;
683     }
684
685     if (i == sizeof(object_creation)/sizeof(object_creation[0]))
686     {
687         FIXME("%s: no class found.\n", debugstr_guid(rclsid));
688         return CLASS_E_CLASSNOTAVAILABLE;
689     }
690
691     factory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*factory));
692     if (factory == NULL) return E_OUTOFMEMORY;
693
694     factory->IClassFactory_iface.lpVtbl = &IClassFactory_Vtbl;
695     factory->ref = 1;
696
697     factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
698
699     *ppv = factory;
700     return S_OK;
701 }
702
703
704 /*******************************************************************************
705  * DllCanUnloadNow [DDRAW.@]  Determines whether the DLL is in use.
706  *
707  * RETURNS
708  *    Success: S_OK
709  *    Failure: S_FALSE
710  */
711 HRESULT WINAPI DllCanUnloadNow(void)
712 {
713     TRACE("\n");
714
715     return S_FALSE;
716 }
717
718
719 /***********************************************************************
720  *              DllRegisterServer (DDRAW.@)
721  */
722 HRESULT WINAPI DllRegisterServer(void)
723 {
724     return __wine_register_resources( instance, NULL );
725 }
726
727 /***********************************************************************
728  *              DllUnregisterServer (DDRAW.@)
729  */
730 HRESULT WINAPI DllUnregisterServer(void)
731 {
732     return __wine_unregister_resources( instance, NULL );
733 }
734
735 /*******************************************************************************
736  * DestroyCallback
737  *
738  * Callback function for the EnumSurfaces call in DllMain.
739  * Dumps some surface info and releases the surface
740  *
741  * Params:
742  *  surf: The enumerated surface
743  *  desc: it's description
744  *  context: Pointer to the ddraw impl
745  *
746  * Returns:
747  *  DDENUMRET_OK;
748  *******************************************************************************/
749 static HRESULT WINAPI
750 DestroyCallback(IDirectDrawSurface7 *surf,
751                 DDSURFACEDESC2 *desc,
752                 void *context)
753 {
754     IDirectDrawSurfaceImpl *Impl = impl_from_IDirectDrawSurface7(surf);
755     ULONG ref7, ref4, ref3, ref2, ref1, iface_count;
756
757     ref7 = IDirectDrawSurface7_Release(surf);  /* For the EnumSurfaces */
758     IDirectDrawSurface4_AddRef(&Impl->IDirectDrawSurface4_iface);
759     ref4 = IDirectDrawSurface4_Release(&Impl->IDirectDrawSurface4_iface);
760     IDirectDrawSurface3_AddRef(&Impl->IDirectDrawSurface3_iface);
761     ref3 = IDirectDrawSurface3_Release(&Impl->IDirectDrawSurface3_iface);
762     IDirectDrawSurface2_AddRef(&Impl->IDirectDrawSurface2_iface);
763     ref2 = IDirectDrawSurface2_Release(&Impl->IDirectDrawSurface2_iface);
764     IDirectDrawSurface_AddRef(&Impl->IDirectDrawSurface_iface);
765     ref1 = IDirectDrawSurface_Release(&Impl->IDirectDrawSurface_iface);
766     WARN("Surface %p has an reference counts of 7: %u 4: %u 3: %u 2: %u 1: %u\n",
767             Impl, ref7, ref4, ref3, ref2, ref1);
768
769     /* Skip surfaces which are attached somewhere or which are
770      * part of a complex compound. They will get released when destroying
771      * the root
772      */
773     if( (!Impl->is_complex_root) || (Impl->first_attached != Impl) )
774         return DDENUMRET_OK;
775
776     /* Destroy the surface */
777     iface_count = ddraw_surface_release_iface(Impl);
778     while (iface_count) iface_count = ddraw_surface_release_iface(Impl);
779
780     return DDENUMRET_OK;
781 }
782
783 /***********************************************************************
784  * get_config_key
785  *
786  * Reads a config key from the registry. Taken from WineD3D
787  *
788  ***********************************************************************/
789 static inline DWORD get_config_key(HKEY defkey, HKEY appkey, const char* name, char* buffer, DWORD size)
790 {
791     if (0 != appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0;
792     if (0 != defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0;
793     return ERROR_FILE_NOT_FOUND;
794 }
795
796 /***********************************************************************
797  * DllMain (DDRAW.0)
798  *
799  * Could be used to register DirectDraw drivers, if we have more than
800  * one. Also used to destroy any objects left at unload if the
801  * app didn't release them properly(Gothic 2, Diablo 2, Moto racer, ...)
802  *
803  ***********************************************************************/
804 BOOL WINAPI
805 DllMain(HINSTANCE hInstDLL,
806         DWORD Reason,
807         LPVOID lpv)
808 {
809     TRACE("(%p,%x,%p)\n", hInstDLL, Reason, lpv);
810     if (Reason == DLL_PROCESS_ATTACH)
811     {
812         char buffer[MAX_PATH+10];
813         DWORD size = sizeof(buffer);
814         HKEY hkey = 0;
815         HKEY appkey = 0;
816         WNDCLASSA wc;
817         DWORD len;
818
819         /* Register the window class. This is used to create a hidden window
820          * for D3D rendering, if the application didn't pass one. It can also
821          * be used for creating a device window from SetCooperativeLevel(). */
822         wc.style = CS_HREDRAW | CS_VREDRAW;
823         wc.lpfnWndProc = DefWindowProcA;
824         wc.cbClsExtra = 0;
825         wc.cbWndExtra = 0;
826         wc.hInstance = hInstDLL;
827         wc.hIcon = 0;
828         wc.hCursor = 0;
829         wc.hbrBackground = GetStockObject(BLACK_BRUSH);
830         wc.lpszMenuName = NULL;
831         wc.lpszClassName = DDRAW_WINDOW_CLASS_NAME;
832         if (!RegisterClassA(&wc))
833         {
834             ERR("Failed to register ddraw window class, last error %#x.\n", GetLastError());
835             return FALSE;
836         }
837
838        /* @@ Wine registry key: HKCU\Software\Wine\Direct3D */
839        if ( RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &hkey ) ) hkey = 0;
840
841        len = GetModuleFileNameA( 0, buffer, MAX_PATH );
842        if (len && len < MAX_PATH)
843        {
844             HKEY tmpkey;
845             /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Direct3D */
846             if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
847             {
848                 char *p, *appname = buffer;
849                 if ((p = strrchr( appname, '/' ))) appname = p + 1;
850                 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
851                 strcat( appname, "\\Direct3D" );
852                 TRACE("appname = [%s]\n", appname);
853                 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
854                 RegCloseKey( tmpkey );
855             }
856        }
857
858        if ( 0 != hkey || 0 != appkey )
859        {
860             if ( !get_config_key( hkey, appkey, "DirectDrawRenderer", buffer, size) )
861             {
862                 if (!strcmp(buffer,"gdi"))
863                 {
864                     TRACE("Defaulting to GDI surfaces\n");
865                     DefaultSurfaceType = SURFACE_GDI;
866                 }
867                 else if (!strcmp(buffer,"opengl"))
868                 {
869                     TRACE("Defaulting to opengl surfaces\n");
870                     DefaultSurfaceType = SURFACE_OPENGL;
871                 }
872                 else
873                 {
874                     ERR("Unknown default surface type. Supported are:\n gdi, opengl\n");
875                 }
876             }
877         }
878
879         /* On Windows one can force the refresh rate that DirectDraw uses by
880          * setting an override value in dxdiag.  This is documented in KB315614
881          * (main article), KB230002, and KB217348.  By comparing registry dumps
882          * before and after setting the override, we see that the override value
883          * is stored in HKLM\Software\Microsoft\DirectDraw\ForceRefreshRate as a
884          * DWORD that represents the refresh rate to force.  We use this
885          * registry entry to modify the behavior of SetDisplayMode so that Wine
886          * users can override the refresh rate in a Windows-compatible way.
887          *
888          * dxdiag will not accept a refresh rate lower than 40 or higher than
889          * 120 so this value should be within that range.  It is, of course,
890          * possible for a user to set the registry entry value directly so that
891          * assumption might not hold.
892          *
893          * There is no current mechanism for setting this value through the Wine
894          * GUI.  It would be most appropriate to set this value through a dxdiag
895          * clone, but it may be sufficient to use winecfg.
896          *
897          * TODO: Create a mechanism for setting this value through the Wine GUI.
898          */
899         if ( !RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectDraw", &hkey ) )
900         {
901             DWORD type, data;
902             size = sizeof(data);
903             if (!RegQueryValueExA( hkey, "ForceRefreshRate", NULL, &type, (LPBYTE)&data, &size ) && type == REG_DWORD)
904             {
905                 TRACE("ForceRefreshRate set; overriding refresh rate to %d Hz\n", data);
906                 force_refresh_rate = data;
907             }
908             RegCloseKey( hkey );
909         }
910
911         instance = hInstDLL;
912         DisableThreadLibraryCalls(hInstDLL);
913     }
914     else if (Reason == DLL_PROCESS_DETACH)
915     {
916         if(!list_empty(&global_ddraw_list))
917         {
918             struct list *entry, *entry2;
919             WARN("There are still existing DirectDraw interfaces. Wine bug or buggy application?\n");
920
921             /* We remove elements from this loop */
922             LIST_FOR_EACH_SAFE(entry, entry2, &global_ddraw_list)
923             {
924                 HRESULT hr;
925                 DDSURFACEDESC2 desc;
926                 int i;
927                 IDirectDrawImpl *ddraw = LIST_ENTRY(entry, IDirectDrawImpl, ddraw_list_entry);
928
929                 WARN("DDraw %p has a refcount of %d\n", ddraw, ddraw->ref7 + ddraw->ref4 + ddraw->ref3 + ddraw->ref2 + ddraw->ref1);
930
931                 /* Add references to each interface to avoid freeing them unexpectedly */
932                 IDirectDraw_AddRef(&ddraw->IDirectDraw_iface);
933                 IDirectDraw2_AddRef(&ddraw->IDirectDraw2_iface);
934                 IDirectDraw3_AddRef(&ddraw->IDirectDraw3_iface);
935                 IDirectDraw4_AddRef(&ddraw->IDirectDraw4_iface);
936                 IDirectDraw7_AddRef(&ddraw->IDirectDraw7_iface);
937
938                 /* Does a D3D device exist? Destroy it
939                     * TODO: Destroy all Vertex buffers, Lights, Materials
940                     * and execute buffers too
941                     */
942                 if(ddraw->d3ddevice)
943                 {
944                     WARN("DDraw %p has d3ddevice %p attached\n", ddraw, ddraw->d3ddevice);
945                     while(IDirect3DDevice7_Release((IDirect3DDevice7 *)ddraw->d3ddevice));
946                 }
947
948                 /* Try to release the objects
949                     * Do an EnumSurfaces to find any hanging surfaces
950                     */
951                 memset(&desc, 0, sizeof(desc));
952                 desc.dwSize = sizeof(desc);
953                 for(i = 0; i <= 1; i++)
954                 {
955                     hr = IDirectDraw7_EnumSurfaces(&ddraw->IDirectDraw7_iface, DDENUMSURFACES_ALL,
956                             &desc, ddraw, DestroyCallback);
957                     if(hr != D3D_OK)
958                         ERR("(%p) EnumSurfaces failed, prepare for trouble\n", ddraw);
959                 }
960
961                 /* Check the surface count */
962                 if(ddraw->surfaces > 0)
963                     ERR("DDraw %p still has %d surfaces attached\n", ddraw, ddraw->surfaces);
964
965                 /* Release all hanging references to destroy the objects. This
966                     * restores the screen mode too
967                     */
968                 while(IDirectDraw_Release(&ddraw->IDirectDraw_iface));
969                 while(IDirectDraw2_Release(&ddraw->IDirectDraw2_iface));
970                 while(IDirectDraw3_Release(&ddraw->IDirectDraw3_iface));
971                 while(IDirectDraw4_Release(&ddraw->IDirectDraw4_iface));
972                 while(IDirectDraw7_Release(&ddraw->IDirectDraw7_iface));
973             }
974         }
975
976         /* Unregister the window class. */
977         UnregisterClassA(DDRAW_WINDOW_CLASS_NAME, hInstDLL);
978     }
979
980     return TRUE;
981 }