dinput: Add Lithuanian translation.
[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_OPENGL;
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
279     if (SUCCEEDED(hr))
280     {
281         hr = IDirectDraw_Initialize(*DD, GUID);
282         if (FAILED(hr))
283             IDirectDraw_Release(*DD);
284     }
285
286     return hr;
287 }
288
289 /***********************************************************************
290  * DirectDrawCreateEx (DDRAW.@)
291  *
292  * Only creates new IDirectDraw7 interfaces, supposed to fail if legacy
293  * interfaces are requested.
294  *
295  * Arguments, return values: See DDRAW_Create
296  *
297  ***********************************************************************/
298 HRESULT WINAPI DECLSPEC_HOTPATCH
299 DirectDrawCreateEx(GUID *guid,
300                    LPVOID *dd,
301                    REFIID iid,
302                    IUnknown *UnkOuter)
303 {
304     HRESULT hr;
305
306     TRACE("driver_guid %s, ddraw %p, interface_iid %s, outer_unknown %p.\n",
307             debugstr_guid(guid), dd, debugstr_guid(iid), UnkOuter);
308
309     if (!IsEqualGUID(iid, &IID_IDirectDraw7))
310         return DDERR_INVALIDPARAMS;
311
312     EnterCriticalSection(&ddraw_cs);
313     hr = DDRAW_Create(guid, dd, UnkOuter, iid);
314     LeaveCriticalSection(&ddraw_cs);
315
316     if (SUCCEEDED(hr))
317     {
318         IDirectDraw7 *ddraw7 = *(IDirectDraw7 **)dd;
319         hr = IDirectDraw7_Initialize(ddraw7, guid);
320         if (FAILED(hr))
321             IDirectDraw7_Release(ddraw7);
322     }
323
324     return hr;
325 }
326
327 /***********************************************************************
328  * DirectDrawEnumerateA (DDRAW.@)
329  *
330  * Enumerates legacy ddraw drivers, ascii version. We only have one
331  * driver, which relays to WineD3D. If we were sufficiently cool,
332  * we could offer various interfaces, which use a different default surface
333  * implementation, but I think it's better to offer this choice in
334  * winecfg, because some apps use the default driver, so we would need
335  * a winecfg option anyway, and there shouldn't be 2 ways to set one setting
336  *
337  * Arguments:
338  *  Callback: Callback function from the app
339  *  Context: Argument to the call back.
340  *
341  * Returns:
342  *  DD_OK on success
343  *  E_INVALIDARG if the Callback caused a page fault
344  *
345  *
346  ***********************************************************************/
347 HRESULT WINAPI DirectDrawEnumerateA(LPDDENUMCALLBACKA Callback, void *Context)
348 {
349     TRACE("callback %p, context %p.\n", Callback, Context);
350
351     TRACE(" Enumerating default DirectDraw HAL interface\n");
352     /* We only have one driver */
353     __TRY
354     {
355         static CHAR driver_desc[] = "DirectDraw HAL",
356         driver_name[] = "display";
357
358         Callback(NULL, driver_desc, driver_name, Context);
359     }
360     __EXCEPT_PAGE_FAULT
361     {
362         return DDERR_INVALIDPARAMS;
363     }
364     __ENDTRY
365
366     TRACE(" End of enumeration\n");
367     return DD_OK;
368 }
369
370 /***********************************************************************
371  * DirectDrawEnumerateExA (DDRAW.@)
372  *
373  * Enumerates DirectDraw7 drivers, ascii version. See
374  * the comments above DirectDrawEnumerateA for more details.
375  *
376  * The Flag member is not supported right now.
377  *
378  ***********************************************************************/
379 HRESULT WINAPI DirectDrawEnumerateExA(LPDDENUMCALLBACKEXA Callback, void *Context, DWORD Flags)
380 {
381     TRACE("callback %p, context %p, flags %#x.\n", Callback, Context, Flags);
382
383     if (Flags & ~(DDENUM_ATTACHEDSECONDARYDEVICES |
384                   DDENUM_DETACHEDSECONDARYDEVICES |
385                   DDENUM_NONDISPLAYDEVICES))
386         return DDERR_INVALIDPARAMS;
387
388     if (Flags)
389         FIXME("flags 0x%08x not handled\n", Flags);
390
391     TRACE("Enumerating default DirectDraw HAL interface\n");
392
393     /* We only have one driver by now */
394     __TRY
395     {
396         static CHAR driver_desc[] = "DirectDraw HAL",
397         driver_name[] = "display";
398
399         /* QuickTime expects the description "DirectDraw HAL" */
400         Callback(NULL, driver_desc, driver_name, Context, 0);
401     }
402     __EXCEPT_PAGE_FAULT
403     {
404         return DDERR_INVALIDPARAMS;
405     }
406     __ENDTRY;
407
408     TRACE("End of enumeration\n");
409     return DD_OK;
410 }
411
412 /***********************************************************************
413  * DirectDrawEnumerateW (DDRAW.@)
414  *
415  * Enumerates legacy drivers, unicode version.
416  * This function is not implemented on Windows.
417  *
418  ***********************************************************************/
419 HRESULT WINAPI DirectDrawEnumerateW(LPDDENUMCALLBACKW callback, void *context)
420 {
421     TRACE("callback %p, context %p.\n", callback, context);
422
423     if (!callback)
424         return DDERR_INVALIDPARAMS;
425     else
426         return DDERR_UNSUPPORTED;
427 }
428
429 /***********************************************************************
430  * DirectDrawEnumerateExW (DDRAW.@)
431  *
432  * Enumerates DirectDraw7 drivers, unicode version.
433  * This function is not implemented on Windows.
434  *
435  ***********************************************************************/
436 HRESULT WINAPI DirectDrawEnumerateExW(LPDDENUMCALLBACKEXW callback, void *context, DWORD flags)
437 {
438     TRACE("callback %p, context %p, flags %#x.\n", callback, context, flags);
439
440     return DDERR_UNSUPPORTED;
441 }
442
443 /***********************************************************************
444  * Classfactory implementation.
445  ***********************************************************************/
446
447 /***********************************************************************
448  * CF_CreateDirectDraw
449  *
450  * DDraw creation function for the class factory
451  *
452  * Params:
453  *  UnkOuter: Set to NULL
454  *  iid: ID of the wanted interface
455  *  obj: Address to pass the interface pointer back
456  *
457  * Returns
458  *  DD_OK / DDERR*, see DDRAW_Create
459  *
460  ***********************************************************************/
461 static HRESULT
462 CF_CreateDirectDraw(IUnknown* UnkOuter, REFIID iid,
463                     void **obj)
464 {
465     HRESULT hr;
466
467     TRACE("outer_unknown %p, riid %s, object %p.\n", UnkOuter, debugstr_guid(iid), obj);
468
469     EnterCriticalSection(&ddraw_cs);
470     hr = DDRAW_Create(NULL, obj, UnkOuter, iid);
471     LeaveCriticalSection(&ddraw_cs);
472     return hr;
473 }
474
475 /***********************************************************************
476  * CF_CreateDirectDraw
477  *
478  * Clipper creation function for the class factory
479  *
480  * Params:
481  *  UnkOuter: Set to NULL
482  *  iid: ID of the wanted interface
483  *  obj: Address to pass the interface pointer back
484  *
485  * Returns
486  *  DD_OK / DDERR*, see DDRAW_Create
487  *
488  ***********************************************************************/
489 static HRESULT
490 CF_CreateDirectDrawClipper(IUnknown* UnkOuter, REFIID riid,
491                               void **obj)
492 {
493     HRESULT hr;
494     IDirectDrawClipper *Clip;
495
496     TRACE("outer_unknown %p, riid %s, object %p.\n", UnkOuter, debugstr_guid(riid), obj);
497
498     EnterCriticalSection(&ddraw_cs);
499     hr = DirectDrawCreateClipper(0, &Clip, UnkOuter);
500     if (hr != DD_OK)
501     {
502         LeaveCriticalSection(&ddraw_cs);
503         return hr;
504     }
505
506     hr = IDirectDrawClipper_QueryInterface(Clip, riid, obj);
507     IDirectDrawClipper_Release(Clip);
508
509     LeaveCriticalSection(&ddraw_cs);
510     return hr;
511 }
512
513 static const struct object_creation_info object_creation[] =
514 {
515     { &CLSID_DirectDraw,        CF_CreateDirectDraw },
516     { &CLSID_DirectDraw7,       CF_CreateDirectDraw },
517     { &CLSID_DirectDrawClipper, CF_CreateDirectDrawClipper }
518 };
519
520
521 /******************************************************************************
522  * DirectDraw ClassFactory implementation
523  ******************************************************************************/
524 typedef struct
525 {
526     IClassFactory IClassFactory_iface;
527
528     LONG ref;
529     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID iid, LPVOID *ppObj);
530 } IClassFactoryImpl;
531
532 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
533 {
534     return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
535 }
536
537 /*******************************************************************************
538  * IDirectDrawClassFactory::QueryInterface
539  *
540  * QueryInterface for the class factory
541  *
542  * PARAMS
543  *    riid   Reference to identifier of queried interface
544  *    ppv    Address to return the interface pointer at
545  *
546  * RETURNS
547  *    Success: S_OK
548  *    Failure: E_NOINTERFACE
549  *
550  *******************************************************************************/
551 static HRESULT WINAPI IDirectDrawClassFactoryImpl_QueryInterface(IClassFactory *iface, REFIID riid,
552         void **obj)
553 {
554     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
555
556     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obj);
557
558     if (IsEqualGUID(riid, &IID_IUnknown)
559         || IsEqualGUID(riid, &IID_IClassFactory))
560     {
561         IClassFactory_AddRef(iface);
562         *obj = This;
563         return S_OK;
564     }
565
566     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),obj);
567     return E_NOINTERFACE;
568 }
569
570 /*******************************************************************************
571  * IDirectDrawClassFactory::AddRef
572  *
573  * AddRef for the class factory
574  *
575  * RETURNS
576  *  The new refcount
577  *
578  *******************************************************************************/
579 static ULONG WINAPI IDirectDrawClassFactoryImpl_AddRef(IClassFactory *iface)
580 {
581     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
582     ULONG ref = InterlockedIncrement(&This->ref);
583
584     TRACE("%p increasing refcount to %u.\n", This, ref);
585
586     return ref;
587 }
588
589 /*******************************************************************************
590  * IDirectDrawClassFactory::Release
591  *
592  * Release for the class factory. If the refcount falls to 0, the object
593  * is destroyed
594  *
595  * RETURNS
596  *  The new refcount
597  *
598  *******************************************************************************/
599 static ULONG WINAPI IDirectDrawClassFactoryImpl_Release(IClassFactory *iface)
600 {
601     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
602     ULONG ref = InterlockedDecrement(&This->ref);
603
604     TRACE("%p decreasing refcount to %u.\n", This, ref);
605
606     if (ref == 0)
607         HeapFree(GetProcessHeap(), 0, This);
608
609     return ref;
610 }
611
612
613 /*******************************************************************************
614  * IDirectDrawClassFactory::CreateInstance
615  *
616  * What is this? Seems to create DirectDraw objects...
617  *
618  * Params
619  *  The usual things???
620  *
621  * RETURNS
622  *  ???
623  *
624  *******************************************************************************/
625 static HRESULT WINAPI IDirectDrawClassFactoryImpl_CreateInstance(IClassFactory *iface,
626         IUnknown *UnkOuter, REFIID riid, void **obj)
627 {
628     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
629
630     TRACE("iface %p, outer_unknown %p, riid %s, object %p.\n",
631             iface, UnkOuter, debugstr_guid(riid), obj);
632
633     return This->pfnCreateInstance(UnkOuter, riid, obj);
634 }
635
636 /*******************************************************************************
637  * IDirectDrawClassFactory::LockServer
638  *
639  * What is this?
640  *
641  * Params
642  *  ???
643  *
644  * RETURNS
645  *  S_OK, because it's a stub
646  *
647  *******************************************************************************/
648 static HRESULT WINAPI IDirectDrawClassFactoryImpl_LockServer(IClassFactory *iface, BOOL dolock)
649 {
650     FIXME("iface %p, dolock %#x stub!\n", iface, dolock);
651
652     return S_OK;
653 }
654
655 /*******************************************************************************
656  * The class factory VTable
657  *******************************************************************************/
658 static const IClassFactoryVtbl IClassFactory_Vtbl =
659 {
660     IDirectDrawClassFactoryImpl_QueryInterface,
661     IDirectDrawClassFactoryImpl_AddRef,
662     IDirectDrawClassFactoryImpl_Release,
663     IDirectDrawClassFactoryImpl_CreateInstance,
664     IDirectDrawClassFactoryImpl_LockServer
665 };
666
667 /*******************************************************************************
668  * DllGetClassObject [DDRAW.@]
669  * Retrieves class object from a DLL object
670  *
671  * NOTES
672  *    Docs say returns STDAPI
673  *
674  * PARAMS
675  *    rclsid [I] CLSID for the class object
676  *    riid   [I] Reference to identifier of interface for class object
677  *    ppv    [O] Address of variable to receive interface pointer for riid
678  *
679  * RETURNS
680  *    Success: S_OK
681  *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
682  *             E_UNEXPECTED
683  */
684 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
685 {
686     unsigned int i;
687     IClassFactoryImpl *factory;
688
689     TRACE("rclsid %s, riid %s, object %p.\n",
690             debugstr_guid(rclsid), debugstr_guid(riid), ppv);
691
692     if (!IsEqualGUID(&IID_IClassFactory, riid)
693             && !IsEqualGUID(&IID_IUnknown, riid))
694         return E_NOINTERFACE;
695
696     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
697     {
698         if (IsEqualGUID(object_creation[i].clsid, rclsid))
699             break;
700     }
701
702     if (i == sizeof(object_creation)/sizeof(object_creation[0]))
703     {
704         FIXME("%s: no class found.\n", debugstr_guid(rclsid));
705         return CLASS_E_CLASSNOTAVAILABLE;
706     }
707
708     factory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*factory));
709     if (factory == NULL) return E_OUTOFMEMORY;
710
711     factory->IClassFactory_iface.lpVtbl = &IClassFactory_Vtbl;
712     factory->ref = 1;
713
714     factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
715
716     *ppv = factory;
717     return S_OK;
718 }
719
720
721 /*******************************************************************************
722  * DllCanUnloadNow [DDRAW.@]  Determines whether the DLL is in use.
723  *
724  * RETURNS
725  *    Success: S_OK
726  *    Failure: S_FALSE
727  */
728 HRESULT WINAPI DllCanUnloadNow(void)
729 {
730     TRACE("\n");
731
732     return S_FALSE;
733 }
734
735
736 /***********************************************************************
737  *              DllRegisterServer (DDRAW.@)
738  */
739 HRESULT WINAPI DllRegisterServer(void)
740 {
741     return __wine_register_resources( instance );
742 }
743
744 /***********************************************************************
745  *              DllUnregisterServer (DDRAW.@)
746  */
747 HRESULT WINAPI DllUnregisterServer(void)
748 {
749     return __wine_unregister_resources( instance );
750 }
751
752 /*******************************************************************************
753  * DestroyCallback
754  *
755  * Callback function for the EnumSurfaces call in DllMain.
756  * Dumps some surface info and releases the surface
757  *
758  * Params:
759  *  surf: The enumerated surface
760  *  desc: it's description
761  *  context: Pointer to the ddraw impl
762  *
763  * Returns:
764  *  DDENUMRET_OK;
765  *******************************************************************************/
766 static HRESULT WINAPI
767 DestroyCallback(IDirectDrawSurface7 *surf,
768                 DDSURFACEDESC2 *desc,
769                 void *context)
770 {
771     IDirectDrawSurfaceImpl *Impl = impl_from_IDirectDrawSurface7(surf);
772     ULONG ref7, ref4, ref3, ref2, ref1, gamma_count, iface_count;
773
774     ref7 = IDirectDrawSurface7_Release(surf);  /* For the EnumSurfaces */
775     IDirectDrawSurface4_AddRef(&Impl->IDirectDrawSurface4_iface);
776     ref4 = IDirectDrawSurface4_Release(&Impl->IDirectDrawSurface4_iface);
777     IDirectDrawSurface3_AddRef(&Impl->IDirectDrawSurface3_iface);
778     ref3 = IDirectDrawSurface3_Release(&Impl->IDirectDrawSurface3_iface);
779     IDirectDrawSurface2_AddRef(&Impl->IDirectDrawSurface2_iface);
780     ref2 = IDirectDrawSurface2_Release(&Impl->IDirectDrawSurface2_iface);
781     IDirectDrawSurface_AddRef(&Impl->IDirectDrawSurface_iface);
782     ref1 = IDirectDrawSurface_Release(&Impl->IDirectDrawSurface_iface);
783     IDirectDrawGammaControl_AddRef(&Impl->IDirectDrawGammaControl_iface);
784     gamma_count = IDirectDrawGammaControl_Release(&Impl->IDirectDrawGammaControl_iface);
785     WARN("Surface %p has an reference counts of 7: %u 4: %u 3: %u 2: %u 1: %u gamma: %u\n",
786             Impl, ref7, ref4, ref3, ref2, ref1, gamma_count);
787
788     /* Skip surfaces which are attached somewhere or which are
789      * part of a complex compound. They will get released when destroying
790      * the root
791      */
792     if( (!Impl->is_complex_root) || (Impl->first_attached != Impl) )
793         return DDENUMRET_OK;
794
795     /* Destroy the surface */
796     iface_count = ddraw_surface_release_iface(Impl);
797     while (iface_count) iface_count = ddraw_surface_release_iface(Impl);
798
799     return DDENUMRET_OK;
800 }
801
802 /***********************************************************************
803  * get_config_key
804  *
805  * Reads a config key from the registry. Taken from WineD3D
806  *
807  ***********************************************************************/
808 static inline DWORD get_config_key(HKEY defkey, HKEY appkey, const char* name, char* buffer, DWORD size)
809 {
810     if (0 != appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0;
811     if (0 != defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0;
812     return ERROR_FILE_NOT_FOUND;
813 }
814
815 /***********************************************************************
816  * DllMain (DDRAW.0)
817  *
818  * Could be used to register DirectDraw drivers, if we have more than
819  * one. Also used to destroy any objects left at unload if the
820  * app didn't release them properly(Gothic 2, Diablo 2, Moto racer, ...)
821  *
822  ***********************************************************************/
823 BOOL WINAPI
824 DllMain(HINSTANCE hInstDLL,
825         DWORD Reason,
826         LPVOID lpv)
827 {
828     TRACE("(%p,%x,%p)\n", hInstDLL, Reason, lpv);
829     if (Reason == DLL_PROCESS_ATTACH)
830     {
831         char buffer[MAX_PATH+10];
832         DWORD size = sizeof(buffer);
833         HKEY hkey = 0;
834         HKEY appkey = 0;
835         WNDCLASSA wc;
836         DWORD len;
837
838         /* Register the window class. This is used to create a hidden window
839          * for D3D rendering, if the application didn't pass one. It can also
840          * be used for creating a device window from SetCooperativeLevel(). */
841         wc.style = CS_HREDRAW | CS_VREDRAW;
842         wc.lpfnWndProc = DefWindowProcA;
843         wc.cbClsExtra = 0;
844         wc.cbWndExtra = 0;
845         wc.hInstance = hInstDLL;
846         wc.hIcon = 0;
847         wc.hCursor = 0;
848         wc.hbrBackground = GetStockObject(BLACK_BRUSH);
849         wc.lpszMenuName = NULL;
850         wc.lpszClassName = DDRAW_WINDOW_CLASS_NAME;
851         if (!RegisterClassA(&wc))
852         {
853             ERR("Failed to register ddraw window class, last error %#x.\n", GetLastError());
854             return FALSE;
855         }
856
857        /* @@ Wine registry key: HKCU\Software\Wine\Direct3D */
858        if ( RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &hkey ) ) hkey = 0;
859
860        len = GetModuleFileNameA( 0, buffer, MAX_PATH );
861        if (len && len < MAX_PATH)
862        {
863             HKEY tmpkey;
864             /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Direct3D */
865             if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
866             {
867                 char *p, *appname = buffer;
868                 if ((p = strrchr( appname, '/' ))) appname = p + 1;
869                 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
870                 strcat( appname, "\\Direct3D" );
871                 TRACE("appname = [%s]\n", appname);
872                 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
873                 RegCloseKey( tmpkey );
874             }
875        }
876
877        if ( 0 != hkey || 0 != appkey )
878        {
879             if ( !get_config_key( hkey, appkey, "DirectDrawRenderer", buffer, size) )
880             {
881                 if (!strcmp(buffer,"gdi"))
882                 {
883                     TRACE("Defaulting to GDI surfaces\n");
884                     DefaultSurfaceType = SURFACE_GDI;
885                 }
886                 else if (!strcmp(buffer,"opengl"))
887                 {
888                     TRACE("Defaulting to opengl surfaces\n");
889                     DefaultSurfaceType = SURFACE_OPENGL;
890                 }
891                 else
892                 {
893                     ERR("Unknown default surface type. Supported are:\n gdi, opengl\n");
894                 }
895             }
896         }
897
898         /* On Windows one can force the refresh rate that DirectDraw uses by
899          * setting an override value in dxdiag.  This is documented in KB315614
900          * (main article), KB230002, and KB217348.  By comparing registry dumps
901          * before and after setting the override, we see that the override value
902          * is stored in HKLM\Software\Microsoft\DirectDraw\ForceRefreshRate as a
903          * DWORD that represents the refresh rate to force.  We use this
904          * registry entry to modify the behavior of SetDisplayMode so that Wine
905          * users can override the refresh rate in a Windows-compatible way.
906          *
907          * dxdiag will not accept a refresh rate lower than 40 or higher than
908          * 120 so this value should be within that range.  It is, of course,
909          * possible for a user to set the registry entry value directly so that
910          * assumption might not hold.
911          *
912          * There is no current mechanism for setting this value through the Wine
913          * GUI.  It would be most appropriate to set this value through a dxdiag
914          * clone, but it may be sufficient to use winecfg.
915          *
916          * TODO: Create a mechanism for setting this value through the Wine GUI.
917          */
918         if ( !RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectDraw", &hkey ) )
919         {
920             DWORD type, data;
921             size = sizeof(data);
922             if (!RegQueryValueExA( hkey, "ForceRefreshRate", NULL, &type, (LPBYTE)&data, &size ) && type == REG_DWORD)
923             {
924                 TRACE("ForceRefreshRate set; overriding refresh rate to %d Hz\n", data);
925                 force_refresh_rate = data;
926             }
927             RegCloseKey( hkey );
928         }
929
930         instance = hInstDLL;
931         DisableThreadLibraryCalls(hInstDLL);
932     }
933     else if (Reason == DLL_PROCESS_DETACH)
934     {
935         if(!list_empty(&global_ddraw_list))
936         {
937             struct list *entry, *entry2;
938             WARN("There are still existing DirectDraw interfaces. Wine bug or buggy application?\n");
939
940             /* We remove elements from this loop */
941             LIST_FOR_EACH_SAFE(entry, entry2, &global_ddraw_list)
942             {
943                 HRESULT hr;
944                 DDSURFACEDESC2 desc;
945                 int i;
946                 IDirectDrawImpl *ddraw = LIST_ENTRY(entry, IDirectDrawImpl, ddraw_list_entry);
947
948                 WARN("DDraw %p has a refcount of %d\n", ddraw, ddraw->ref7 + ddraw->ref4 + ddraw->ref3 + ddraw->ref2 + ddraw->ref1);
949
950                 /* Add references to each interface to avoid freeing them unexpectedly */
951                 IDirectDraw_AddRef(&ddraw->IDirectDraw_iface);
952                 IDirectDraw2_AddRef(&ddraw->IDirectDraw2_iface);
953                 IDirectDraw4_AddRef(&ddraw->IDirectDraw4_iface);
954                 IDirectDraw7_AddRef(&ddraw->IDirectDraw7_iface);
955
956                 /* Does a D3D device exist? Destroy it
957                     * TODO: Destroy all Vertex buffers, Lights, Materials
958                     * and execute buffers too
959                     */
960                 if(ddraw->d3ddevice)
961                 {
962                     WARN("DDraw %p has d3ddevice %p attached\n", ddraw, ddraw->d3ddevice);
963                     while(IDirect3DDevice7_Release(&ddraw->d3ddevice->IDirect3DDevice7_iface));
964                 }
965
966                 /* Try to release the objects
967                     * Do an EnumSurfaces to find any hanging surfaces
968                     */
969                 memset(&desc, 0, sizeof(desc));
970                 desc.dwSize = sizeof(desc);
971                 for(i = 0; i <= 1; i++)
972                 {
973                     hr = IDirectDraw7_EnumSurfaces(&ddraw->IDirectDraw7_iface, DDENUMSURFACES_ALL,
974                             &desc, ddraw, DestroyCallback);
975                     if(hr != D3D_OK)
976                         ERR("(%p) EnumSurfaces failed, prepare for trouble\n", ddraw);
977                 }
978
979                 if (!list_empty(&ddraw->surface_list))
980                     ERR("DDraw %p still has surfaces attached.\n", ddraw);
981
982                 /* Release all hanging references to destroy the objects. This
983                     * restores the screen mode too
984                     */
985                 while(IDirectDraw_Release(&ddraw->IDirectDraw_iface));
986                 while(IDirectDraw2_Release(&ddraw->IDirectDraw2_iface));
987                 while(IDirectDraw4_Release(&ddraw->IDirectDraw4_iface));
988                 while(IDirectDraw7_Release(&ddraw->IDirectDraw7_iface));
989             }
990         }
991
992         /* Unregister the window class. */
993         UnregisterClassA(DDRAW_WINDOW_CLASS_NAME, hInstDLL);
994     }
995
996     return TRUE;
997 }