main.c 30.9 KB
Newer Older
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 10
 *
 * This file contains the (internal) driver registration functions,
 * driver enumeration APIs and DirectDraw creation functions.
11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 31
#define DDRAW_INIT_GUID
#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
enum wined3d_surface_type DefaultSurfaceType = WINED3D_SURFACE_TYPE_OPENGL;
41

42 43
static struct list global_ddraw_list = LIST_INIT(global_ddraw_list);

44 45
static HINSTANCE instance;

46 47 48
/* value of ForceRefreshRate */
DWORD force_refresh_rate = 0;

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
/* Handle table functions */
BOOL ddraw_handle_table_init(struct ddraw_handle_table *t, UINT initial_size)
{
    t->entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, initial_size * sizeof(*t->entries));
    if (!t->entries)
    {
        ERR("Failed to allocate handle table memory.\n");
        return FALSE;
    }
    t->free_entries = NULL;
    t->table_size = initial_size;
    t->entry_count = 0;

    return TRUE;
}

void ddraw_handle_table_destroy(struct ddraw_handle_table *t)
{
    HeapFree(GetProcessHeap(), 0, t->entries);
    memset(t, 0, sizeof(*t));
}

DWORD ddraw_allocate_handle(struct ddraw_handle_table *t, void *object, enum ddraw_handle_type type)
{
    struct ddraw_handle_entry *entry;

    if (t->free_entries)
    {
        DWORD idx = t->free_entries - t->entries;
        /* Use a free handle */
        entry = t->free_entries;
        if (entry->type != DDRAW_HANDLE_FREE)
        {
            ERR("Handle %#x (%p) is in the free list, but has type %#x.\n", idx, entry->object, entry->type);
            return DDRAW_INVALID_HANDLE;
        }
        t->free_entries = entry->object;
        entry->object = object;
        entry->type = type;

        return idx;
    }

    if (!(t->entry_count < t->table_size))
    {
        /* Grow the table */
        UINT new_size = t->table_size + (t->table_size >> 1);
        struct ddraw_handle_entry *new_entries = HeapReAlloc(GetProcessHeap(),
                0, t->entries, new_size * sizeof(*t->entries));
        if (!new_entries)
        {
            ERR("Failed to grow the handle table.\n");
            return DDRAW_INVALID_HANDLE;
        }
        t->entries = new_entries;
        t->table_size = new_size;
    }

    entry = &t->entries[t->entry_count];
    entry->object = object;
    entry->type = type;

    return t->entry_count++;
}

void *ddraw_free_handle(struct ddraw_handle_table *t, DWORD handle, enum ddraw_handle_type type)
{
    struct ddraw_handle_entry *entry;
    void *object;

    if (handle == DDRAW_INVALID_HANDLE || handle >= t->entry_count)
    {
        WARN("Invalid handle %#x passed.\n", handle);
        return NULL;
    }

    entry = &t->entries[handle];
    if (entry->type != type)
    {
        WARN("Handle %#x (%p) is not of type %#x.\n", handle, entry->object, type);
        return NULL;
    }

    object = entry->object;
    entry->object = t->free_entries;
    entry->type = DDRAW_HANDLE_FREE;
    t->free_entries = entry;

    return object;
}

void *ddraw_get_object(struct ddraw_handle_table *t, DWORD handle, enum ddraw_handle_type type)
{
    struct ddraw_handle_entry *entry;

    if (handle == DDRAW_INVALID_HANDLE || handle >= t->entry_count)
    {
        WARN("Invalid handle %#x passed.\n", handle);
        return NULL;
    }

    entry = &t->entries[handle];
    if (entry->type != type)
    {
        WARN("Handle %#x (%p) is not of type %#x.\n", handle, entry->object, type);
        return NULL;
    }

    return entry->object;
}

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
/***********************************************************************
 *
 * Helper function for DirectDrawCreate and friends
 * Creates a new DDraw interface with the given REFIID
 *
 * Interfaces that can be created:
 *  IDirectDraw, IDirectDraw2, IDirectDraw4, IDirectDraw7
 *  IDirect3D, IDirect3D2, IDirect3D3, IDirect3D7. (Does Windows return
 *  IDirect3D interfaces?)
 *
 * Arguments:
 *  guid: ID of the requested driver, NULL for the default driver.
 *        The GUID can be queried with DirectDrawEnumerate(Ex)A/W
 *  DD: Used to return the pointer to the created object
 *  UnkOuter: For aggregation, which is unsupported. Must be NULL
 *  iid: requested version ID.
 *
 * Returns:
178
 *  DD_OK if the Interface was created successfully
179 180 181 182 183
 *  CLASS_E_NOAGGREGATION if UnkOuter is not NULL
 *  E_OUTOFMEMORY if some allocation failed
 *
 ***********************************************************************/
static HRESULT
184
DDRAW_Create(const GUID *guid,
185 186 187
             void **DD,
             IUnknown *UnkOuter,
             REFIID iid)
188
{
189
    enum wined3d_device_type device_type;
190
    struct ddraw *ddraw;
191
    HRESULT hr;
192

193 194
    TRACE("driver_guid %s, ddraw %p, outer_unknown %p, interface_iid %s.\n",
            debugstr_guid(guid), DD, UnkOuter, debugstr_guid(iid));
195

196 197
    *DD = NULL;

198 199 200 201 202 203 204 205 206
    /* We don't care about this guids. Well, there's no special guid anyway
     * OK, we could
     */
    if (guid == (GUID *) DDCREATE_EMULATIONONLY)
    {
        /* Use the reference device id. This doesn't actually change anything,
         * WineD3D always uses OpenGL for D3D rendering. One could make it request
         * indirect rendering
         */
207
        device_type = WINED3D_DEVICE_TYPE_REF;
208
    }
209 210
    else if(guid == (GUID *) DDCREATE_HARDWAREONLY)
    {
211
        device_type = WINED3D_DEVICE_TYPE_HAL;
212
    }
213 214
    else
    {
215
        device_type = 0;
216 217
    }

218
    /* DDraw doesn't support aggregation, according to msdn */
219 220
    if (UnkOuter != NULL)
        return CLASS_E_NOAGGREGATION;
221

222
    /* DirectDraw creation comes here */
223 224
    ddraw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ddraw));
    if (!ddraw)
225 226 227
    {
        ERR("Out of memory when creating DirectDraw\n");
        return E_OUTOFMEMORY;
228
    }
229

230
    hr = ddraw_init(ddraw, device_type);
231
    if (FAILED(hr))
232
    {
233
        WARN("Failed to initialize ddraw object, hr %#x.\n", hr);
234
        HeapFree(GetProcessHeap(), 0, ddraw);
235
        return hr;
236 237
    }

238 239 240 241 242 243
    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);
244

245
    return hr;
246 247 248
}

/***********************************************************************
249 250 251 252 253 254 255 256
 * DirectDrawCreate (DDRAW.@)
 *
 * Creates legacy DirectDraw Interfaces. Can't create IDirectDraw7
 * interfaces in theory
 *
 * Arguments, return values: See DDRAW_Create
 *
 ***********************************************************************/
257
HRESULT WINAPI DECLSPEC_HOTPATCH
258
DirectDrawCreate(GUID *GUID,
259
                 LPDIRECTDRAW *DD,
260
                 IUnknown *UnkOuter)
261
{
262
    HRESULT hr;
263 264 265

    TRACE("driver_guid %s, ddraw %p, outer_unknown %p.\n",
            debugstr_guid(GUID), DD, UnkOuter);
266

267
    wined3d_mutex_lock();
268
    hr = DDRAW_Create(GUID, (void **) DD, UnkOuter, &IID_IDirectDraw);
269
    wined3d_mutex_unlock();
270 271 272 273 274 275 276 277

    if (SUCCEEDED(hr))
    {
        hr = IDirectDraw_Initialize(*DD, GUID);
        if (FAILED(hr))
            IDirectDraw_Release(*DD);
    }

278
    return hr;
279 280 281
}

/***********************************************************************
282 283 284 285 286 287 288 289
 * DirectDrawCreateEx (DDRAW.@)
 *
 * Only creates new IDirectDraw7 interfaces, supposed to fail if legacy
 * interfaces are requested.
 *
 * Arguments, return values: See DDRAW_Create
 *
 ***********************************************************************/
290
HRESULT WINAPI DECLSPEC_HOTPATCH
291 292
DirectDrawCreateEx(GUID *guid,
                   LPVOID *dd,
293 294
                   REFIID iid,
                   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 302
    if (!IsEqualGUID(iid, &IID_IDirectDraw7))
        return DDERR_INVALIDPARAMS;
303

304
    wined3d_mutex_lock();
305
    hr = DDRAW_Create(guid, dd, UnkOuter, iid);
306
    wined3d_mutex_unlock();
307 308 309

    if (SUCCEEDED(hr))
    {
310 311
        IDirectDraw7 *ddraw7 = *(IDirectDraw7 **)dd;
        hr = IDirectDraw7_Initialize(ddraw7, guid);
312 313 314 315
        if (FAILED(hr))
            IDirectDraw7_Release(ddraw7);
    }

316
    return hr;
317 318
}

319
/***********************************************************************
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
 * DirectDrawEnumerateA (DDRAW.@)
 *
 * Enumerates legacy ddraw drivers, ascii version. We only have one
 * driver, which relays to WineD3D. If we were sufficiently cool,
 * we could offer various interfaces, which use a different default surface
 * implementation, but I think it's better to offer this choice in
 * winecfg, because some apps use the default driver, so we would need
 * a winecfg option anyway, and there shouldn't be 2 ways to set one setting
 *
 * Arguments:
 *  Callback: Callback function from the app
 *  Context: Argument to the call back.
 *
 * Returns:
 *  DD_OK on success
 *  E_INVALIDARG if the Callback caused a page fault
 *
 *
 ***********************************************************************/
339
HRESULT WINAPI DirectDrawEnumerateA(LPDDENUMCALLBACKA Callback, void *Context)
340
{
341
    TRACE("callback %p, context %p.\n", Callback, Context);
342

343 344 345
    TRACE(" Enumerating default DirectDraw HAL interface\n");
    /* We only have one driver */
    __TRY
346
    {
347 348 349
        static CHAR driver_desc[] = "DirectDraw HAL",
        driver_name[] = "display";

350
        Callback(NULL, driver_desc, driver_name, Context);
351
    }
352
    __EXCEPT_PAGE_FAULT
353
    {
354
        return DDERR_INVALIDPARAMS;
355
    }
356
    __ENDTRY
357

358 359 360
    TRACE(" End of enumeration\n");
    return DD_OK;
}
361

362 363 364 365 366 367 368 369 370
/***********************************************************************
 * DirectDrawEnumerateExA (DDRAW.@)
 *
 * Enumerates DirectDraw7 drivers, ascii version. See
 * the comments above DirectDrawEnumerateA for more details.
 *
 * The Flag member is not supported right now.
 *
 ***********************************************************************/
371
HRESULT WINAPI DirectDrawEnumerateExA(LPDDENUMCALLBACKEXA Callback, void *Context, DWORD Flags)
372
{
373
    TRACE("callback %p, context %p, flags %#x.\n", Callback, Context, Flags);
374 375 376 377 378 379 380 381 382

    if (Flags & ~(DDENUM_ATTACHEDSECONDARYDEVICES |
                  DDENUM_DETACHEDSECONDARYDEVICES |
                  DDENUM_NONDISPLAYDEVICES))
        return DDERR_INVALIDPARAMS;

    if (Flags)
        FIXME("flags 0x%08x not handled\n", Flags);

383
    TRACE("Enumerating default DirectDraw HAL interface\n");
384

385 386
    /* We only have one driver by now */
    __TRY
387
    {
388 389 390
        static CHAR driver_desc[] = "DirectDraw HAL",
        driver_name[] = "display";

391
        /* QuickTime expects the description "DirectDraw HAL" */
392
        Callback(NULL, driver_desc, driver_name, Context, 0);
393
    }
394 395
    __EXCEPT_PAGE_FAULT
    {
396
        return DDERR_INVALIDPARAMS;
397 398
    }
    __ENDTRY;
399

400 401
    TRACE("End of enumeration\n");
    return DD_OK;
402 403
}

404
/***********************************************************************
405
 * DirectDrawEnumerateW (DDRAW.@)
406
 *
407 408
 * Enumerates legacy drivers, unicode version.
 * This function is not implemented on Windows.
409 410
 *
 ***********************************************************************/
411
HRESULT WINAPI DirectDrawEnumerateW(LPDDENUMCALLBACKW callback, void *context)
412
{
413
    TRACE("callback %p, context %p.\n", callback, context);
414

415
    if (!callback)
416 417 418 419
        return DDERR_INVALIDPARAMS;
    else
        return DDERR_UNSUPPORTED;
}
420

421
/***********************************************************************
422
 * DirectDrawEnumerateExW (DDRAW.@)
423
 *
424 425
 * Enumerates DirectDraw7 drivers, unicode version.
 * This function is not implemented on Windows.
426 427
 *
 ***********************************************************************/
428
HRESULT WINAPI DirectDrawEnumerateExW(LPDDENUMCALLBACKEXW callback, void *context, DWORD flags)
429
{
430
    TRACE("callback %p, context %p, flags %#x.\n", callback, context, flags);
431 432 433

    return DDERR_UNSUPPORTED;
}
434

435 436 437
/***********************************************************************
 * Classfactory implementation.
 ***********************************************************************/
438

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
/***********************************************************************
 * CF_CreateDirectDraw
 *
 * DDraw creation function for the class factory
 *
 * Params:
 *  UnkOuter: Set to NULL
 *  iid: ID of the wanted interface
 *  obj: Address to pass the interface pointer back
 *
 * Returns
 *  DD_OK / DDERR*, see DDRAW_Create
 *
 ***********************************************************************/
static HRESULT
CF_CreateDirectDraw(IUnknown* UnkOuter, REFIID iid,
                    void **obj)
456 457 458
{
    HRESULT hr;

459
    TRACE("outer_unknown %p, riid %s, object %p.\n", UnkOuter, debugstr_guid(iid), obj);
460

461
    wined3d_mutex_lock();
462
    hr = DDRAW_Create(NULL, obj, UnkOuter, iid);
463 464
    wined3d_mutex_unlock();

465
    return hr;
466 467
}

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
/***********************************************************************
 * CF_CreateDirectDraw
 *
 * Clipper creation function for the class factory
 *
 * Params:
 *  UnkOuter: Set to NULL
 *  iid: ID of the wanted interface
 *  obj: Address to pass the interface pointer back
 *
 * Returns
 *  DD_OK / DDERR*, see DDRAW_Create
 *
 ***********************************************************************/
static HRESULT
CF_CreateDirectDrawClipper(IUnknown* UnkOuter, REFIID riid,
                              void **obj)
485
{
486 487 488
    HRESULT hr;
    IDirectDrawClipper *Clip;

489 490
    TRACE("outer_unknown %p, riid %s, object %p.\n", UnkOuter, debugstr_guid(riid), obj);

491
    wined3d_mutex_lock();
492
    hr = DirectDrawCreateClipper(0, &Clip, UnkOuter);
493 494
    if (hr != DD_OK)
    {
495
        wined3d_mutex_unlock();
496 497
        return hr;
    }
498

499 500
    hr = IDirectDrawClipper_QueryInterface(Clip, riid, obj);
    IDirectDrawClipper_Release(Clip);
501

502 503
    wined3d_mutex_unlock();

504 505
    return hr;
}
506 507 508

static const struct object_creation_info object_creation[] =
{
509 510 511
    { &CLSID_DirectDraw,        CF_CreateDirectDraw },
    { &CLSID_DirectDraw7,       CF_CreateDirectDraw },
    { &CLSID_DirectDrawClipper, CF_CreateDirectDrawClipper }
512 513
};

514
struct ddraw_class_factory
515 516 517 518 519
{
    IClassFactory IClassFactory_iface;

    LONG ref;
    HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID iid, LPVOID *ppObj);
520
};
521

522
static inline struct ddraw_class_factory *impl_from_IClassFactory(IClassFactory *iface)
523
{
524
    return CONTAINING_RECORD(iface, struct ddraw_class_factory, IClassFactory_iface);
525 526
}

527 528 529 530 531 532 533 534 535 536 537 538 539 540
/*******************************************************************************
 * IDirectDrawClassFactory::QueryInterface
 *
 * QueryInterface for the class factory
 *
 * PARAMS
 *    riid   Reference to identifier of queried interface
 *    ppv    Address to return the interface pointer at
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: E_NOINTERFACE
 *
 *******************************************************************************/
541
static HRESULT WINAPI ddraw_class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
542
{
543
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
544

545
    if (IsEqualGUID(riid, &IID_IUnknown)
546
        || IsEqualGUID(riid, &IID_IClassFactory))
547
    {
548
        IClassFactory_AddRef(iface);
549
        *out = iface;
550
        return S_OK;
551 552
    }

553 554
    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));

555 556 557
    return E_NOINTERFACE;
}

558 559 560 561 562 563 564 565 566
/*******************************************************************************
 * IDirectDrawClassFactory::AddRef
 *
 * AddRef for the class factory
 *
 * RETURNS
 *  The new refcount
 *
 *******************************************************************************/
567
static ULONG WINAPI ddraw_class_factory_AddRef(IClassFactory *iface)
568
{
569 570
    struct ddraw_class_factory *factory = impl_from_IClassFactory(iface);
    ULONG ref = InterlockedIncrement(&factory->ref);
571

572
    TRACE("%p increasing refcount to %u.\n", factory, ref);
573

574
    return ref;
575 576
}

577 578 579 580 581 582 583 584 585 586
/*******************************************************************************
 * IDirectDrawClassFactory::Release
 *
 * Release for the class factory. If the refcount falls to 0, the object
 * is destroyed
 *
 * RETURNS
 *  The new refcount
 *
 *******************************************************************************/
587
static ULONG WINAPI ddraw_class_factory_Release(IClassFactory *iface)
588
{
589 590
    struct ddraw_class_factory *factory = impl_from_IClassFactory(iface);
    ULONG ref = InterlockedDecrement(&factory->ref);
591

592
    TRACE("%p decreasing refcount to %u.\n", factory, ref);
593

594 595
    if (!ref)
        HeapFree(GetProcessHeap(), 0, factory);
596

597
    return ref;
598 599
}

600

601 602 603 604 605 606
/*******************************************************************************
 * IDirectDrawClassFactory::CreateInstance
 *
 * What is this? Seems to create DirectDraw objects...
 *
 * Params
Austin English's avatar
Austin English committed
607
 *  The usual things???
608 609 610 611 612
 *
 * RETURNS
 *  ???
 *
 *******************************************************************************/
613 614
static HRESULT WINAPI ddraw_class_factory_CreateInstance(IClassFactory *iface,
        IUnknown *outer_unknown, REFIID riid, void **out)
615
{
616
    struct ddraw_class_factory *factory = impl_from_IClassFactory(iface);
617

618 619
    TRACE("iface %p, outer_unknown %p, riid %s, out %p.\n",
            iface, outer_unknown, debugstr_guid(riid), out);
620

621
    return factory->pfnCreateInstance(outer_unknown, riid, out);
622 623
}

624 625 626 627 628 629 630 631 632 633 634 635
/*******************************************************************************
 * IDirectDrawClassFactory::LockServer
 *
 * What is this?
 *
 * Params
 *  ???
 *
 * RETURNS
 *  S_OK, because it's a stub
 *
 *******************************************************************************/
636
static HRESULT WINAPI ddraw_class_factory_LockServer(IClassFactory *iface, BOOL dolock)
637
{
638 639
    FIXME("iface %p, dolock %#x stub!\n", iface, dolock);

640 641 642
    return S_OK;
}

643 644 645 646
/*******************************************************************************
 * The class factory VTable
 *******************************************************************************/
static const IClassFactoryVtbl IClassFactory_Vtbl =
647
{
648 649 650 651 652
    ddraw_class_factory_QueryInterface,
    ddraw_class_factory_AddRef,
    ddraw_class_factory_Release,
    ddraw_class_factory_CreateInstance,
    ddraw_class_factory_LockServer
653 654 655
};

/*******************************************************************************
656
 * DllGetClassObject [DDRAW.@]
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
 * Retrieves class object from a DLL object
 *
 * NOTES
 *    Docs say returns STDAPI
 *
 * PARAMS
 *    rclsid [I] CLSID for the class object
 *    riid   [I] Reference to identifier of interface for class object
 *    ppv    [O] Address of variable to receive interface pointer for riid
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
 *             E_UNEXPECTED
 */
672
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
673
{
674
    struct ddraw_class_factory *factory;
675
    unsigned int i;
676

677 678
    TRACE("rclsid %s, riid %s, object %p.\n",
            debugstr_guid(rclsid), debugstr_guid(riid), ppv);
679

680 681 682
    if (!IsEqualGUID(&IID_IClassFactory, riid)
            && !IsEqualGUID(&IID_IUnknown, riid))
        return E_NOINTERFACE;
683 684 685

    for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
    {
686 687
        if (IsEqualGUID(object_creation[i].clsid, rclsid))
            break;
688 689 690 691
    }

    if (i == sizeof(object_creation)/sizeof(object_creation[0]))
    {
692 693
        FIXME("%s: no class found.\n", debugstr_guid(rclsid));
        return CLASS_E_CLASSNOTAVAILABLE;
694
    }
695

696
    factory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*factory));
697 698
    if (factory == NULL) return E_OUTOFMEMORY;

699
    factory->IClassFactory_iface.lpVtbl = &IClassFactory_Vtbl;
700 701 702 703
    factory->ref = 1;

    factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;

704
    *ppv = factory;
705
    return S_OK;
706 707 708 709
}


/*******************************************************************************
710
 * DllCanUnloadNow [DDRAW.@]  Determines whether the DLL is in use.
711 712 713 714 715
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: S_FALSE
 */
716 717
HRESULT WINAPI DllCanUnloadNow(void)
{
718 719
    TRACE("\n");

720
    return S_FALSE;
721
}
722

723 724 725 726 727 728

/***********************************************************************
 *		DllRegisterServer (DDRAW.@)
 */
HRESULT WINAPI DllRegisterServer(void)
{
729
    return __wine_register_resources( instance );
730 731 732 733 734 735 736
}

/***********************************************************************
 *		DllUnregisterServer (DDRAW.@)
 */
HRESULT WINAPI DllUnregisterServer(void)
{
737
    return __wine_unregister_resources( instance );
738 739
}

740 741 742 743 744 745 746 747 748 749 750 751 752 753
/*******************************************************************************
 * DestroyCallback
 *
 * Callback function for the EnumSurfaces call in DllMain.
 * Dumps some surface info and releases the surface
 *
 * Params:
 *  surf: The enumerated surface
 *  desc: it's description
 *  context: Pointer to the ddraw impl
 *
 * Returns:
 *  DDENUMRET_OK;
 *******************************************************************************/
754
static HRESULT WINAPI
755 756 757
DestroyCallback(IDirectDrawSurface7 *surf,
                DDSURFACEDESC2 *desc,
                void *context)
758
{
759
    struct ddraw_surface *Impl = impl_from_IDirectDrawSurface7(surf);
760
    ULONG ref7, ref4, ref3, ref2, ref1, gamma_count, iface_count;
761

762
    ref7 = IDirectDrawSurface7_Release(surf);  /* For the EnumSurfaces */
763 764 765 766 767 768
    ref4 = Impl->ref4;
    ref3 = Impl->ref3;
    ref2 = Impl->ref2;
    ref1 = Impl->ref1;
    gamma_count = Impl->gamma_count;

769 770
    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);
771 772 773 774 775

    /* Skip surfaces which are attached somewhere or which are
     * part of a complex compound. They will get released when destroying
     * the root
     */
776
    if( (!Impl->is_complex_root) || (Impl->first_attached != Impl) )
777 778 779
        return DDENUMRET_OK;

    /* Destroy the surface */
780 781
    iface_count = ddraw_surface_release_iface(Impl);
    while (iface_count) iface_count = ddraw_surface_release_iface(Impl);
782 783

    return DDENUMRET_OK;
784 785
}

786
/***********************************************************************
787 788 789 790 791
 * get_config_key
 *
 * Reads a config key from the registry. Taken from WineD3D
 *
 ***********************************************************************/
792
static inline DWORD get_config_key(HKEY defkey, HKEY appkey, const char* name, char* buffer, DWORD size)
793
{
794 795 796 797
    if (0 != appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0;
    if (0 != defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0;
    return ERROR_FILE_NOT_FOUND;
}
798

799 800 801 802 803 804 805 806 807 808 809
/***********************************************************************
 * DllMain (DDRAW.0)
 *
 * Could be used to register DirectDraw drivers, if we have more than
 * one. Also used to destroy any objects left at unload if the
 * app didn't release them properly(Gothic 2, Diablo 2, Moto racer, ...)
 *
 ***********************************************************************/
BOOL WINAPI
DllMain(HINSTANCE hInstDLL,
        DWORD Reason,
810
        LPVOID lpv)
811
{
812
    TRACE("(%p,%x,%p)\n", hInstDLL, Reason, lpv);
813
    if (Reason == DLL_PROCESS_ATTACH)
814
    {
815 816 817 818
        char buffer[MAX_PATH+10];
        DWORD size = sizeof(buffer);
        HKEY hkey = 0;
        HKEY appkey = 0;
819
        WNDCLASSA wc;
820 821
        DWORD len;

822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
        /* Register the window class. This is used to create a hidden window
         * for D3D rendering, if the application didn't pass one. It can also
         * be used for creating a device window from SetCooperativeLevel(). */
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = DefWindowProcA;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstDLL;
        wc.hIcon = 0;
        wc.hCursor = 0;
        wc.hbrBackground = GetStockObject(BLACK_BRUSH);
        wc.lpszMenuName = NULL;
        wc.lpszClassName = DDRAW_WINDOW_CLASS_NAME;
        if (!RegisterClassA(&wc))
        {
            ERR("Failed to register ddraw window class, last error %#x.\n", GetLastError());
            return FALSE;
        }

841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
       /* @@ Wine registry key: HKCU\Software\Wine\Direct3D */
       if ( RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &hkey ) ) hkey = 0;

       len = GetModuleFileNameA( 0, buffer, MAX_PATH );
       if (len && len < MAX_PATH)
       {
            HKEY tmpkey;
            /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Direct3D */
            if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
            {
                char *p, *appname = buffer;
                if ((p = strrchr( appname, '/' ))) appname = p + 1;
                if ((p = strrchr( appname, '\\' ))) appname = p + 1;
                strcat( appname, "\\Direct3D" );
                TRACE("appname = [%s]\n", appname);
                if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
                RegCloseKey( tmpkey );
            }
       }

       if ( 0 != hkey || 0 != appkey )
       {
            if ( !get_config_key( hkey, appkey, "DirectDrawRenderer", buffer, size) )
            {
                if (!strcmp(buffer,"gdi"))
                {
                    TRACE("Defaulting to GDI surfaces\n");
868
                    DefaultSurfaceType = WINED3D_SURFACE_TYPE_GDI;
869 870 871 872
                }
                else if (!strcmp(buffer,"opengl"))
                {
                    TRACE("Defaulting to opengl surfaces\n");
873
                    DefaultSurfaceType = WINED3D_SURFACE_TYPE_OPENGL;
874 875 876
                }
                else
                {
877
                    ERR("Unknown default surface type. Supported are:\n gdi, opengl\n");
878 879 880
                }
            }
        }
881

882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
        /* On Windows one can force the refresh rate that DirectDraw uses by
         * setting an override value in dxdiag.  This is documented in KB315614
         * (main article), KB230002, and KB217348.  By comparing registry dumps
         * before and after setting the override, we see that the override value
         * is stored in HKLM\Software\Microsoft\DirectDraw\ForceRefreshRate as a
         * DWORD that represents the refresh rate to force.  We use this
         * registry entry to modify the behavior of SetDisplayMode so that Wine
         * users can override the refresh rate in a Windows-compatible way.
         *
         * dxdiag will not accept a refresh rate lower than 40 or higher than
         * 120 so this value should be within that range.  It is, of course,
         * possible for a user to set the registry entry value directly so that
         * assumption might not hold.
         *
         * There is no current mechanism for setting this value through the Wine
         * GUI.  It would be most appropriate to set this value through a dxdiag
         * clone, but it may be sufficient to use winecfg.
         *
         * TODO: Create a mechanism for setting this value through the Wine GUI.
         */
        if ( !RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectDraw", &hkey ) )
        {
            DWORD type, data;
            size = sizeof(data);
            if (!RegQueryValueExA( hkey, "ForceRefreshRate", NULL, &type, (LPBYTE)&data, &size ) && type == REG_DWORD)
            {
                TRACE("ForceRefreshRate set; overriding refresh rate to %d Hz\n", data);
                force_refresh_rate = data;
            }
            RegCloseKey( hkey );
        }

914
        instance = hInstDLL;
915
        DisableThreadLibraryCalls(hInstDLL);
916 917 918
    }
    else if (Reason == DLL_PROCESS_DETACH)
    {
919
        if(!list_empty(&global_ddraw_list))
920
        {
921 922 923
            struct list *entry, *entry2;
            WARN("There are still existing DirectDraw interfaces. Wine bug or buggy application?\n");

Austin English's avatar
Austin English committed
924
            /* We remove elements from this loop */
925
            LIST_FOR_EACH_SAFE(entry, entry2, &global_ddraw_list)
926
            {
927
                struct ddraw *ddraw = LIST_ENTRY(entry, struct ddraw, ddraw_list_entry);
928 929 930 931
                HRESULT hr;
                DDSURFACEDESC2 desc;
                int i;

932
                WARN("DDraw %p has a refcount of %d\n", ddraw, ddraw->ref7 + ddraw->ref4 + ddraw->ref3 + ddraw->ref2 + ddraw->ref1);
933

Austin English's avatar
Austin English committed
934
                /* Add references to each interface to avoid freeing them unexpectedly */
935
                IDirectDraw_AddRef(&ddraw->IDirectDraw_iface);
936
                IDirectDraw2_AddRef(&ddraw->IDirectDraw2_iface);
937
                IDirectDraw4_AddRef(&ddraw->IDirectDraw4_iface);
938
                IDirectDraw7_AddRef(&ddraw->IDirectDraw7_iface);
939 940 941

                /* Does a D3D device exist? Destroy it
                    * TODO: Destroy all Vertex buffers, Lights, Materials
Austin English's avatar
Austin English committed
942
                    * and execute buffers too
943 944 945 946
                    */
                if(ddraw->d3ddevice)
                {
                    WARN("DDraw %p has d3ddevice %p attached\n", ddraw, ddraw->d3ddevice);
947
                    while(IDirect3DDevice7_Release(&ddraw->d3ddevice->IDirect3DDevice7_iface));
948
                }
949

950 951 952 953 954 955
                /* 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);

956 957 958 959 960 961
                /* Try to release the objects
                    * Do an EnumSurfaces to find any hanging surfaces
                    */
                memset(&desc, 0, sizeof(desc));
                desc.dwSize = sizeof(desc);
                for(i = 0; i <= 1; i++)
962
                {
963 964
                    hr = IDirectDraw7_EnumSurfaces(&ddraw->IDirectDraw7_iface, DDENUMSURFACES_ALL,
                            &desc, ddraw, DestroyCallback);
965 966
                    if(hr != D3D_OK)
                        ERR("(%p) EnumSurfaces failed, prepare for trouble\n", ddraw);
967
                }
968

969 970
                if (!list_empty(&ddraw->surface_list))
                    ERR("DDraw %p still has surfaces attached.\n", ddraw);
971 972 973 974

                /* Release all hanging references to destroy the objects. This
                    * restores the screen mode too
                    */
975
                while(IDirectDraw_Release(&ddraw->IDirectDraw_iface));
976
                while(IDirectDraw2_Release(&ddraw->IDirectDraw2_iface));
977
                while(IDirectDraw4_Release(&ddraw->IDirectDraw4_iface));
978
                while(IDirectDraw7_Release(&ddraw->IDirectDraw7_iface));
979
            }
980
        }
981 982 983

        /* Unregister the window class. */
        UnregisterClassA(DDRAW_WINDOW_CLASS_NAME, hInstDLL);
984
    }
985 986 987

    return TRUE;
}