wined3d: Remove IWineD3DSurface::GetImplType() from the public interface.
[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 = (IDirectDrawSurfaceImpl *)surf;
755     ULONG ref;
756
757     ref = IDirectDrawSurface7_Release(surf);  /* For the EnumSurfaces */
758     WARN("Surface %p has an reference count of %d\n", Impl, ref);
759
760     /* Skip surfaces which are attached somewhere or which are
761      * part of a complex compound. They will get released when destroying
762      * the root
763      */
764     if( (!Impl->is_complex_root) || (Impl->first_attached != Impl) )
765         return DDENUMRET_OK;
766
767     /* Destroy the surface */
768     while(ref) ref = IDirectDrawSurface7_Release(surf);
769
770     return DDENUMRET_OK;
771 }
772
773 /***********************************************************************
774  * get_config_key
775  *
776  * Reads a config key from the registry. Taken from WineD3D
777  *
778  ***********************************************************************/
779 static inline DWORD get_config_key(HKEY defkey, HKEY appkey, const char* name, char* buffer, DWORD size)
780 {
781     if (0 != appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0;
782     if (0 != defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0;
783     return ERROR_FILE_NOT_FOUND;
784 }
785
786 /***********************************************************************
787  * DllMain (DDRAW.0)
788  *
789  * Could be used to register DirectDraw drivers, if we have more than
790  * one. Also used to destroy any objects left at unload if the
791  * app didn't release them properly(Gothic 2, Diablo 2, Moto racer, ...)
792  *
793  ***********************************************************************/
794 BOOL WINAPI
795 DllMain(HINSTANCE hInstDLL,
796         DWORD Reason,
797         LPVOID lpv)
798 {
799     TRACE("(%p,%x,%p)\n", hInstDLL, Reason, lpv);
800     if (Reason == DLL_PROCESS_ATTACH)
801     {
802         char buffer[MAX_PATH+10];
803         DWORD size = sizeof(buffer);
804         HKEY hkey = 0;
805         HKEY appkey = 0;
806         WNDCLASSA wc;
807         DWORD len;
808
809         /* Register the window class. This is used to create a hidden window
810          * for D3D rendering, if the application didn't pass one. It can also
811          * be used for creating a device window from SetCooperativeLevel(). */
812         wc.style = CS_HREDRAW | CS_VREDRAW;
813         wc.lpfnWndProc = DefWindowProcA;
814         wc.cbClsExtra = 0;
815         wc.cbWndExtra = 0;
816         wc.hInstance = hInstDLL;
817         wc.hIcon = 0;
818         wc.hCursor = 0;
819         wc.hbrBackground = GetStockObject(BLACK_BRUSH);
820         wc.lpszMenuName = NULL;
821         wc.lpszClassName = DDRAW_WINDOW_CLASS_NAME;
822         if (!RegisterClassA(&wc))
823         {
824             ERR("Failed to register ddraw window class, last error %#x.\n", GetLastError());
825             return FALSE;
826         }
827
828        /* @@ Wine registry key: HKCU\Software\Wine\Direct3D */
829        if ( RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &hkey ) ) hkey = 0;
830
831        len = GetModuleFileNameA( 0, buffer, MAX_PATH );
832        if (len && len < MAX_PATH)
833        {
834             HKEY tmpkey;
835             /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Direct3D */
836             if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
837             {
838                 char *p, *appname = buffer;
839                 if ((p = strrchr( appname, '/' ))) appname = p + 1;
840                 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
841                 strcat( appname, "\\Direct3D" );
842                 TRACE("appname = [%s]\n", appname);
843                 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
844                 RegCloseKey( tmpkey );
845             }
846        }
847
848        if ( 0 != hkey || 0 != appkey )
849        {
850             if ( !get_config_key( hkey, appkey, "DirectDrawRenderer", buffer, size) )
851             {
852                 if (!strcmp(buffer,"gdi"))
853                 {
854                     TRACE("Defaulting to GDI surfaces\n");
855                     DefaultSurfaceType = SURFACE_GDI;
856                 }
857                 else if (!strcmp(buffer,"opengl"))
858                 {
859                     TRACE("Defaulting to opengl surfaces\n");
860                     DefaultSurfaceType = SURFACE_OPENGL;
861                 }
862                 else
863                 {
864                     ERR("Unknown default surface type. Supported are:\n gdi, opengl\n");
865                 }
866             }
867         }
868
869         /* On Windows one can force the refresh rate that DirectDraw uses by
870          * setting an override value in dxdiag.  This is documented in KB315614
871          * (main article), KB230002, and KB217348.  By comparing registry dumps
872          * before and after setting the override, we see that the override value
873          * is stored in HKLM\Software\Microsoft\DirectDraw\ForceRefreshRate as a
874          * DWORD that represents the refresh rate to force.  We use this
875          * registry entry to modify the behavior of SetDisplayMode so that Wine
876          * users can override the refresh rate in a Windows-compatible way.
877          *
878          * dxdiag will not accept a refresh rate lower than 40 or higher than
879          * 120 so this value should be within that range.  It is, of course,
880          * possible for a user to set the registry entry value directly so that
881          * assumption might not hold.
882          *
883          * There is no current mechanism for setting this value through the Wine
884          * GUI.  It would be most appropriate to set this value through a dxdiag
885          * clone, but it may be sufficient to use winecfg.
886          *
887          * TODO: Create a mechanism for setting this value through the Wine GUI.
888          */
889         if ( !RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectDraw", &hkey ) )
890         {
891             DWORD type, data;
892             size = sizeof(data);
893             if (!RegQueryValueExA( hkey, "ForceRefreshRate", NULL, &type, (LPBYTE)&data, &size ) && type == REG_DWORD)
894             {
895                 TRACE("ForceRefreshRate set; overriding refresh rate to %d Hz\n", data);
896                 force_refresh_rate = data;
897             }
898             RegCloseKey( hkey );
899         }
900
901         instance = hInstDLL;
902         DisableThreadLibraryCalls(hInstDLL);
903     }
904     else if (Reason == DLL_PROCESS_DETACH)
905     {
906         if(!list_empty(&global_ddraw_list))
907         {
908             struct list *entry, *entry2;
909             WARN("There are still existing DirectDraw interfaces. Wine bug or buggy application?\n");
910
911             /* We remove elements from this loop */
912             LIST_FOR_EACH_SAFE(entry, entry2, &global_ddraw_list)
913             {
914                 HRESULT hr;
915                 DDSURFACEDESC2 desc;
916                 int i;
917                 IDirectDrawImpl *ddraw = LIST_ENTRY(entry, IDirectDrawImpl, ddraw_list_entry);
918
919                 WARN("DDraw %p has a refcount of %d\n", ddraw, ddraw->ref7 + ddraw->ref4 + ddraw->ref3 + ddraw->ref2 + ddraw->ref1);
920
921                 /* Add references to each interface to avoid freeing them unexpectedly */
922                 IDirectDraw_AddRef(&ddraw->IDirectDraw_iface);
923                 IDirectDraw2_AddRef(&ddraw->IDirectDraw2_iface);
924                 IDirectDraw3_AddRef(&ddraw->IDirectDraw3_iface);
925                 IDirectDraw4_AddRef(&ddraw->IDirectDraw4_iface);
926                 IDirectDraw7_AddRef(&ddraw->IDirectDraw7_iface);
927
928                 /* Does a D3D device exist? Destroy it
929                     * TODO: Destroy all Vertex buffers, Lights, Materials
930                     * and execute buffers too
931                     */
932                 if(ddraw->d3ddevice)
933                 {
934                     WARN("DDraw %p has d3ddevice %p attached\n", ddraw, ddraw->d3ddevice);
935                     while(IDirect3DDevice7_Release((IDirect3DDevice7 *)ddraw->d3ddevice));
936                 }
937
938                 /* Try to release the objects
939                     * Do an EnumSurfaces to find any hanging surfaces
940                     */
941                 memset(&desc, 0, sizeof(desc));
942                 desc.dwSize = sizeof(desc);
943                 for(i = 0; i <= 1; i++)
944                 {
945                     hr = IDirectDraw7_EnumSurfaces(&ddraw->IDirectDraw7_iface, DDENUMSURFACES_ALL,
946                             &desc, ddraw, DestroyCallback);
947                     if(hr != D3D_OK)
948                         ERR("(%p) EnumSurfaces failed, prepare for trouble\n", ddraw);
949                 }
950
951                 /* Check the surface count */
952                 if(ddraw->surfaces > 0)
953                     ERR("DDraw %p still has %d surfaces attached\n", ddraw, ddraw->surfaces);
954
955                 /* Release all hanging references to destroy the objects. This
956                     * restores the screen mode too
957                     */
958                 while(IDirectDraw_Release(&ddraw->IDirectDraw_iface));
959                 while(IDirectDraw2_Release(&ddraw->IDirectDraw2_iface));
960                 while(IDirectDraw3_Release(&ddraw->IDirectDraw3_iface));
961                 while(IDirectDraw4_Release(&ddraw->IDirectDraw4_iface));
962                 while(IDirectDraw7_Release(&ddraw->IDirectDraw7_iface));
963             }
964         }
965
966         /* Unregister the window class. */
967         UnregisterClassA(DDRAW_WINDOW_CLASS_NAME, hInstDLL);
968     }
969
970     return TRUE;
971 }