ddraw: Avoid LPD3DTRIANGLE.
[wine] / dlls / ddraw / main.c
index c9d5139..e79b471 100644 (file)
@@ -37,7 +37,7 @@
 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
 
 /* The configured default surface */
-WINED3DSURFTYPE DefaultSurfaceType = SURFACE_OPENGL;
+enum wined3d_surface_type DefaultSurfaceType = WINED3D_SURFACE_TYPE_OPENGL;
 
 static struct list global_ddraw_list = LIST_INIT(global_ddraw_list);
 
@@ -46,6 +46,22 @@ static HINSTANCE instance;
 /* value of ForceRefreshRate */
 DWORD force_refresh_rate = 0;
 
+/* Structure for converting DirectDrawEnumerateA to DirectDrawEnumerateExA */
+struct callback_info
+{
+    LPDDENUMCALLBACKA callback;
+    void *context;
+};
+
+/* Enumeration callback for converting DirectDrawEnumerateA to DirectDrawEnumerateExA */
+static HRESULT CALLBACK enum_callback(GUID *guid, char *description, char *driver_name,
+                                      void *context, HMONITOR monitor)
+{
+    const struct callback_info *info = context;
+
+    return info->callback(guid, description, driver_name, info->context);
+}
+
 /* Handle table functions */
 BOOL ddraw_handle_table_init(struct ddraw_handle_table *t, UINT initial_size)
 {
@@ -186,8 +202,8 @@ DDRAW_Create(const GUID *guid,
              IUnknown *UnkOuter,
              REFIID iid)
 {
-    WINED3DDEVTYPE devicetype;
-    IDirectDrawImpl *This;
+    enum wined3d_device_type device_type;
+    struct ddraw *ddraw;
     HRESULT hr;
 
     TRACE("driver_guid %s, ddraw %p, outer_unknown %p, interface_iid %s.\n",
@@ -204,15 +220,15 @@ DDRAW_Create(const GUID *guid,
          * WineD3D always uses OpenGL for D3D rendering. One could make it request
          * indirect rendering
          */
-        devicetype = WINED3DDEVTYPE_REF;
+        device_type = WINED3D_DEVICE_TYPE_REF;
     }
     else if(guid == (GUID *) DDCREATE_HARDWAREONLY)
     {
-        devicetype = WINED3DDEVTYPE_HAL;
+        device_type = WINED3D_DEVICE_TYPE_HAL;
     }
     else
     {
-        devicetype = 0;
+        device_type = 0;
     }
 
     /* DDraw doesn't support aggregation, according to msdn */
@@ -220,25 +236,27 @@ DDRAW_Create(const GUID *guid,
         return CLASS_E_NOAGGREGATION;
 
     /* DirectDraw creation comes here */
-    This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectDrawImpl));
-    if(!This)
+    ddraw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ddraw));
+    if (!ddraw)
     {
         ERR("Out of memory when creating DirectDraw\n");
         return E_OUTOFMEMORY;
     }
 
-    hr = ddraw_init(This, devicetype);
+    hr = ddraw_init(ddraw, device_type);
     if (FAILED(hr))
     {
         WARN("Failed to initialize ddraw object, hr %#x.\n", hr);
-        HeapFree(GetProcessHeap(), 0, This);
+        HeapFree(GetProcessHeap(), 0, ddraw);
         return hr;
     }
 
-    hr = IDirectDraw7_QueryInterface(&This->IDirectDraw7_iface, iid, DD);
-    IDirectDraw7_Release(&This->IDirectDraw7_iface);
-    if (SUCCEEDED(hr)) list_add_head(&global_ddraw_list, &This->ddraw_list_entry);
-    else WARN("Failed to query interface %s from ddraw object %p.\n", debugstr_guid(iid), This);
+    hr = IDirectDraw7_QueryInterface(&ddraw->IDirectDraw7_iface, iid, DD);
+    IDirectDraw7_Release(&ddraw->IDirectDraw7_iface);
+    if (SUCCEEDED(hr))
+        list_add_head(&global_ddraw_list, &ddraw->ddraw_list_entry);
+    else
+        WARN("Failed to query interface %s from ddraw object %p.\n", debugstr_guid(iid), ddraw);
 
     return hr;
 }
@@ -252,25 +270,21 @@ DDRAW_Create(const GUID *guid,
  * Arguments, return values: See DDRAW_Create
  *
  ***********************************************************************/
-HRESULT WINAPI DECLSPEC_HOTPATCH
-DirectDrawCreate(GUID *GUID,
-                 LPDIRECTDRAW *DD,
-                 IUnknown *UnkOuter)
+HRESULT WINAPI DECLSPEC_HOTPATCH DirectDrawCreate(GUID *driver_guid, IDirectDraw **ddraw, IUnknown *outer)
 {
     HRESULT hr;
 
-    TRACE("driver_guid %s, ddraw %p, outer_unknown %p.\n",
-            debugstr_guid(GUID), DD, UnkOuter);
+    TRACE("driver_guid %s, ddraw %p, outer %p.\n",
+            debugstr_guid(driver_guid), ddraw, outer);
 
     wined3d_mutex_lock();
-    hr = DDRAW_Create(GUID, (void **) DD, UnkOuter, &IID_IDirectDraw);
+    hr = DDRAW_Create(driver_guid, (void **)ddraw, outer, &IID_IDirectDraw);
     wined3d_mutex_unlock();
 
     if (SUCCEEDED(hr))
     {
-        hr = IDirectDraw_Initialize(*DD, GUID);
-        if (FAILED(hr))
-            IDirectDraw_Release(*DD);
+        if (FAILED(hr = IDirectDraw_Initialize(*ddraw, driver_guid)))
+            IDirectDraw_Release(*ddraw);
     }
 
     return hr;
@@ -334,27 +348,15 @@ DirectDrawCreateEx(GUID *guid,
  *
  *
  ***********************************************************************/
-HRESULT WINAPI DirectDrawEnumerateA(LPDDENUMCALLBACKA Callback, void *Context)
+HRESULT WINAPI DirectDrawEnumerateA(LPDDENUMCALLBACKA callback, void *context)
 {
-    TRACE("callback %p, context %p.\n", Callback, Context);
+    struct callback_info info;
 
-    TRACE(" Enumerating default DirectDraw HAL interface\n");
-    /* We only have one driver */
-    __TRY
-    {
-        static CHAR driver_desc[] = "DirectDraw HAL",
-        driver_name[] = "display";
-
-        Callback(NULL, driver_desc, driver_name, Context);
-    }
-    __EXCEPT_PAGE_FAULT
-    {
-        return DDERR_INVALIDPARAMS;
-    }
-    __ENDTRY
+    TRACE("callback %p, context %p.\n", callback, context);
 
-    TRACE(" End of enumeration\n");
-    return DD_OK;
+    info.callback = callback;
+    info.context = context;
+    return DirectDrawEnumerateExA(enum_callback, &info, 0x0);
 }
 
 /***********************************************************************
@@ -366,35 +368,73 @@ HRESULT WINAPI DirectDrawEnumerateA(LPDDENUMCALLBACKA Callback, void *Context)
  * The Flag member is not supported right now.
  *
  ***********************************************************************/
-HRESULT WINAPI DirectDrawEnumerateExA(LPDDENUMCALLBACKEXA Callback, void *Context, DWORD Flags)
+HRESULT WINAPI DirectDrawEnumerateExA(LPDDENUMCALLBACKEXA callback, void *context, DWORD flags)
 {
-    TRACE("callback %p, context %p, flags %#x.\n", Callback, Context, Flags);
+    struct wined3d *wined3d;
+
+    TRACE("callback %p, context %p, flags %#x.\n", callback, context, flags);
 
-    if (Flags & ~(DDENUM_ATTACHEDSECONDARYDEVICES |
+    if (flags & ~(DDENUM_ATTACHEDSECONDARYDEVICES |
                   DDENUM_DETACHEDSECONDARYDEVICES |
                   DDENUM_NONDISPLAYDEVICES))
         return DDERR_INVALIDPARAMS;
 
-    if (Flags)
-        FIXME("flags 0x%08x not handled\n", Flags);
+    if (flags)
+        FIXME("flags 0x%08x not handled\n", flags);
 
-    TRACE("Enumerating default DirectDraw HAL interface\n");
+    TRACE("Enumerating ddraw interfaces\n");
+    if (!(wined3d = wined3d_create(7, WINED3D_LEGACY_DEPTH_BIAS)))
+    {
+        if (!(wined3d = wined3d_create(7, WINED3D_LEGACY_DEPTH_BIAS | WINED3D_NO3D)))
+        {
+            WARN("Failed to create a wined3d object.\n");
+            return E_FAIL;
+        }
+
+        WARN("Created a wined3d object without 3D support.\n");
+    }
 
-    /* We only have one driver by now */
     __TRY
     {
+        /* QuickTime expects the description "DirectDraw HAL" */
         static CHAR driver_desc[] = "DirectDraw HAL",
         driver_name[] = "display";
-
-        /* QuickTime expects the description "DirectDraw HAL" */
-        Callback(NULL, driver_desc, driver_name, Context, 0);
+        struct wined3d_adapter_identifier adapter_id;
+        HRESULT hr = S_OK;
+        UINT adapter = 0;
+        BOOL cont_enum;
+
+        /* The Battle.net System Checker expects both a NULL device and a GUID-based device */
+        TRACE("Default interface: DirectDraw HAL\n");
+        cont_enum = callback(NULL, driver_desc, driver_name, context, 0);
+        for (adapter = 0; SUCCEEDED(hr) && cont_enum; adapter++)
+        {
+            char DriverName[512] = "";
+
+            /* The Battle.net System Checker expects the GetAdapterIdentifier DeviceName to match the
+             * Driver Name, so obtain the DeviceName and GUID from D3D. */
+            memset(&adapter_id, 0x0, sizeof(adapter_id));
+            adapter_id.device_name = DriverName;
+            adapter_id.device_name_size = sizeof(DriverName);
+            wined3d_mutex_lock();
+            hr = wined3d_get_adapter_identifier(wined3d, adapter, 0x0, &adapter_id);
+            wined3d_mutex_unlock();
+            if (SUCCEEDED(hr))
+            {
+                TRACE("Interface %d: %s\n", adapter, wine_dbgstr_guid(&adapter_id.device_identifier));
+                cont_enum = callback(&adapter_id.device_identifier, driver_desc,
+                                     adapter_id.device_name, context, 0);
+            }
+        }
     }
     __EXCEPT_PAGE_FAULT
     {
+        wined3d_decref(wined3d);
         return DDERR_INVALIDPARAMS;
     }
     __ENDTRY;
 
+    wined3d_decref(wined3d);
     TRACE("End of enumeration\n");
     return DD_OK;
 }
@@ -509,21 +549,17 @@ static const struct object_creation_info object_creation[] =
     { &CLSID_DirectDrawClipper, CF_CreateDirectDrawClipper }
 };
 
-
-/******************************************************************************
- * DirectDraw ClassFactory implementation
- ******************************************************************************/
-typedef struct
+struct ddraw_class_factory
 {
     IClassFactory IClassFactory_iface;
 
     LONG ref;
     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID iid, LPVOID *ppObj);
-} IClassFactoryImpl;
+};
 
-static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
+static inline struct ddraw_class_factory *impl_from_IClassFactory(IClassFactory *iface)
 {
-    return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
+    return CONTAINING_RECORD(iface, struct ddraw_class_factory, IClassFactory_iface);
 }
 
 /*******************************************************************************
@@ -540,22 +576,20 @@ static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
  *    Failure: E_NOINTERFACE
  *
  *******************************************************************************/
-static HRESULT WINAPI IDirectDrawClassFactoryImpl_QueryInterface(IClassFactory *iface, REFIID riid,
-        void **obj)
+static HRESULT WINAPI ddraw_class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
 {
-    IClassFactoryImpl *This = impl_from_IClassFactory(iface);
-
-    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obj);
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
 
     if (IsEqualGUID(riid, &IID_IUnknown)
         || IsEqualGUID(riid, &IID_IClassFactory))
     {
         IClassFactory_AddRef(iface);
-        *obj = This;
+        *out = iface;
         return S_OK;
     }
 
-    WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),obj);
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
     return E_NOINTERFACE;
 }
 
@@ -568,12 +602,12 @@ static HRESULT WINAPI IDirectDrawClassFactoryImpl_QueryInterface(IClassFactory *
  *  The new refcount
  *
  *******************************************************************************/
-static ULONG WINAPI IDirectDrawClassFactoryImpl_AddRef(IClassFactory *iface)
+static ULONG WINAPI ddraw_class_factory_AddRef(IClassFactory *iface)
 {
-    IClassFactoryImpl *This = impl_from_IClassFactory(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
+    struct ddraw_class_factory *factory = impl_from_IClassFactory(iface);
+    ULONG ref = InterlockedIncrement(&factory->ref);
 
-    TRACE("%p increasing refcount to %u.\n", This, ref);
+    TRACE("%p increasing refcount to %u.\n", factory, ref);
 
     return ref;
 }
@@ -588,15 +622,15 @@ static ULONG WINAPI IDirectDrawClassFactoryImpl_AddRef(IClassFactory *iface)
  *  The new refcount
  *
  *******************************************************************************/
-static ULONG WINAPI IDirectDrawClassFactoryImpl_Release(IClassFactory *iface)
+static ULONG WINAPI ddraw_class_factory_Release(IClassFactory *iface)
 {
-    IClassFactoryImpl *This = impl_from_IClassFactory(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
+    struct ddraw_class_factory *factory = impl_from_IClassFactory(iface);
+    ULONG ref = InterlockedDecrement(&factory->ref);
 
-    TRACE("%p decreasing refcount to %u.\n", This, ref);
+    TRACE("%p decreasing refcount to %u.\n", factory, ref);
 
-    if (ref == 0)
-        HeapFree(GetProcessHeap(), 0, This);
+    if (!ref)
+        HeapFree(GetProcessHeap(), 0, factory);
 
     return ref;
 }
@@ -614,15 +648,15 @@ static ULONG WINAPI IDirectDrawClassFactoryImpl_Release(IClassFactory *iface)
  *  ???
  *
  *******************************************************************************/
-static HRESULT WINAPI IDirectDrawClassFactoryImpl_CreateInstance(IClassFactory *iface,
-        IUnknown *UnkOuter, REFIID riid, void **obj)
+static HRESULT WINAPI ddraw_class_factory_CreateInstance(IClassFactory *iface,
+        IUnknown *outer_unknown, REFIID riid, void **out)
 {
-    IClassFactoryImpl *This = impl_from_IClassFactory(iface);
+    struct ddraw_class_factory *factory = impl_from_IClassFactory(iface);
 
-    TRACE("iface %p, outer_unknown %p, riid %s, object %p.\n",
-            iface, UnkOuter, debugstr_guid(riid), obj);
+    TRACE("iface %p, outer_unknown %p, riid %s, out %p.\n",
+            iface, outer_unknown, debugstr_guid(riid), out);
 
-    return This->pfnCreateInstance(UnkOuter, riid, obj);
+    return factory->pfnCreateInstance(outer_unknown, riid, out);
 }
 
 /*******************************************************************************
@@ -637,7 +671,7 @@ static HRESULT WINAPI IDirectDrawClassFactoryImpl_CreateInstance(IClassFactory *
  *  S_OK, because it's a stub
  *
  *******************************************************************************/
-static HRESULT WINAPI IDirectDrawClassFactoryImpl_LockServer(IClassFactory *iface, BOOL dolock)
+static HRESULT WINAPI ddraw_class_factory_LockServer(IClassFactory *iface, BOOL dolock)
 {
     FIXME("iface %p, dolock %#x stub!\n", iface, dolock);
 
@@ -649,11 +683,11 @@ static HRESULT WINAPI IDirectDrawClassFactoryImpl_LockServer(IClassFactory *ifac
  *******************************************************************************/
 static const IClassFactoryVtbl IClassFactory_Vtbl =
 {
-    IDirectDrawClassFactoryImpl_QueryInterface,
-    IDirectDrawClassFactoryImpl_AddRef,
-    IDirectDrawClassFactoryImpl_Release,
-    IDirectDrawClassFactoryImpl_CreateInstance,
-    IDirectDrawClassFactoryImpl_LockServer
+    ddraw_class_factory_QueryInterface,
+    ddraw_class_factory_AddRef,
+    ddraw_class_factory_Release,
+    ddraw_class_factory_CreateInstance,
+    ddraw_class_factory_LockServer
 };
 
 /*******************************************************************************
@@ -675,8 +709,8 @@ static const IClassFactoryVtbl IClassFactory_Vtbl =
  */
 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
 {
+    struct ddraw_class_factory *factory;
     unsigned int i;
-    IClassFactoryImpl *factory;
 
     TRACE("rclsid %s, riid %s, object %p.\n",
             debugstr_guid(rclsid), debugstr_guid(riid), ppv);
@@ -760,20 +794,16 @@ DestroyCallback(IDirectDrawSurface7 *surf,
                 DDSURFACEDESC2 *desc,
                 void *context)
 {
-    IDirectDrawSurfaceImpl *Impl = impl_from_IDirectDrawSurface7(surf);
+    struct ddraw_surface *Impl = impl_from_IDirectDrawSurface7(surf);
     ULONG ref7, ref4, ref3, ref2, ref1, gamma_count, iface_count;
 
     ref7 = IDirectDrawSurface7_Release(surf);  /* For the EnumSurfaces */
-    IDirectDrawSurface4_AddRef(&Impl->IDirectDrawSurface4_iface);
-    ref4 = IDirectDrawSurface4_Release(&Impl->IDirectDrawSurface4_iface);
-    IDirectDrawSurface3_AddRef(&Impl->IDirectDrawSurface3_iface);
-    ref3 = IDirectDrawSurface3_Release(&Impl->IDirectDrawSurface3_iface);
-    IDirectDrawSurface2_AddRef(&Impl->IDirectDrawSurface2_iface);
-    ref2 = IDirectDrawSurface2_Release(&Impl->IDirectDrawSurface2_iface);
-    IDirectDrawSurface_AddRef(&Impl->IDirectDrawSurface_iface);
-    ref1 = IDirectDrawSurface_Release(&Impl->IDirectDrawSurface_iface);
-    IDirectDrawGammaControl_AddRef(&Impl->IDirectDrawGammaControl_iface);
-    gamma_count = IDirectDrawGammaControl_Release(&Impl->IDirectDrawGammaControl_iface);
+    ref4 = Impl->ref4;
+    ref3 = Impl->ref3;
+    ref2 = Impl->ref2;
+    ref1 = Impl->ref1;
+    gamma_count = Impl->gamma_count;
+
     WARN("Surface %p has an reference counts of 7: %u 4: %u 3: %u 2: %u 1: %u gamma: %u\n",
             Impl, ref7, ref4, ref3, ref2, ref1, gamma_count);
 
@@ -820,6 +850,7 @@ DllMain(HINSTANCE hInstDLL,
     TRACE("(%p,%x,%p)\n", hInstDLL, Reason, lpv);
     if (Reason == DLL_PROCESS_ATTACH)
     {
+        static HMODULE ddraw_self;
         char buffer[MAX_PATH+10];
         DWORD size = sizeof(buffer);
         HKEY hkey = 0;
@@ -873,12 +904,12 @@ DllMain(HINSTANCE hInstDLL,
                 if (!strcmp(buffer,"gdi"))
                 {
                     TRACE("Defaulting to GDI surfaces\n");
-                    DefaultSurfaceType = SURFACE_GDI;
+                    DefaultSurfaceType = WINED3D_SURFACE_TYPE_GDI;
                 }
                 else if (!strcmp(buffer,"opengl"))
                 {
                     TRACE("Defaulting to opengl surfaces\n");
-                    DefaultSurfaceType = SURFACE_OPENGL;
+                    DefaultSurfaceType = WINED3D_SURFACE_TYPE_OPENGL;
                 }
                 else
                 {
@@ -919,6 +950,16 @@ DllMain(HINSTANCE hInstDLL,
             RegCloseKey( hkey );
         }
 
+        /* Prevent the ddraw module from being unloaded. When switching to
+         * exclusive mode, we replace the window proc of the ddraw window. If
+         * an application would unload ddraw from the WM_DESTROY handler for
+         * that window, it would return to unmapped memory and die. Apparently
+         * this is supposed to work on Windows. We should probably use
+         * GET_MODULE_HANDLE_EX_FLAG_PIN for this, but that's not currently
+         * implemented. */
+        if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR *)&ddraw_self, &ddraw_self))
+            ERR("Failed to get own module handle.\n");
+
         instance = hInstDLL;
         DisableThreadLibraryCalls(hInstDLL);
     }
@@ -932,10 +973,10 @@ DllMain(HINSTANCE hInstDLL,
             /* We remove elements from this loop */
             LIST_FOR_EACH_SAFE(entry, entry2, &global_ddraw_list)
             {
+                struct ddraw *ddraw = LIST_ENTRY(entry, struct ddraw, ddraw_list_entry);
                 HRESULT hr;
                 DDSURFACEDESC2 desc;
                 int i;
-                IDirectDrawImpl *ddraw = LIST_ENTRY(entry, IDirectDrawImpl, ddraw_list_entry);
 
                 WARN("DDraw %p has a refcount of %d\n", ddraw, ddraw->ref7 + ddraw->ref4 + ddraw->ref3 + ddraw->ref2 + ddraw->ref1);
 
@@ -945,9 +986,6 @@ DllMain(HINSTANCE hInstDLL,
                 IDirectDraw4_AddRef(&ddraw->IDirectDraw4_iface);
                 IDirectDraw7_AddRef(&ddraw->IDirectDraw7_iface);
 
-                if (ddraw->wined3d_swapchain)
-                    ddraw_destroy_swapchain(ddraw);
-
                 /* Does a D3D device exist? Destroy it
                     * TODO: Destroy all Vertex buffers, Lights, Materials
                     * and execute buffers too
@@ -958,6 +996,12 @@ DllMain(HINSTANCE hInstDLL,
                     while(IDirect3DDevice7_Release(&ddraw->d3ddevice->IDirect3DDevice7_iface));
                 }
 
+                /* Destroy the swapchain after any 3D device. The 3D device
+                 * cleanup code needs a swapchain. Specifically, it tries to
+                 * set the current render target to the front buffer. */
+                if (ddraw->wined3d_swapchain)
+                    ddraw_destroy_swapchain(ddraw);
+
                 /* Try to release the objects
                     * Do an EnumSurfaces to find any hanging surfaces
                     */