main.c 27.7 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 11 12 13 14 15 16 17 18 19 20
 * 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
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 23
 */

24 25
#define DDRAW_INIT_GUID
#include "ddraw_private.h"
26
#include "rpcproxy.h"
27

28
#include "wine/exception.h"
29
#include "winreg.h"
30

31
WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
32

33 34
static struct list global_ddraw_list = LIST_INIT(global_ddraw_list);

35 36
static HINSTANCE instance;

37 38 39
/* value of ForceRefreshRate */
DWORD force_refresh_rate = 0;

40 41 42 43 44 45 46 47
/* Structure for converting DirectDrawEnumerateA to DirectDrawEnumerateExA */
struct callback_info
{
    LPDDENUMCALLBACKA callback;
    void *context;
};

/* Enumeration callback for converting DirectDrawEnumerateA to DirectDrawEnumerateExA */
48
static BOOL CALLBACK enum_callback(GUID *guid, char *description, char *driver_name,
49 50 51 52 53 54 55
                                      void *context, HMONITOR monitor)
{
    const struct callback_info *info = context;

    return info->callback(guid, description, driver_name, info->context);
}

56 57 58 59
static void ddraw_enumerate_secondary_devices(struct wined3d *wined3d, LPDDENUMCALLBACKEXA callback,
                                              void *context)
{
    struct wined3d_adapter_identifier adapter_id;
60
    struct wined3d_adapter *wined3d_adapter;
61
    struct wined3d_output_desc output_desc;
62
    struct wined3d_output *wined3d_output;
63 64 65
    unsigned int interface_count = 0;
    unsigned int adapter_idx = 0;
    unsigned int output_idx;
66
    BOOL cont_enum = TRUE;
67
    HRESULT hr;
68

69
    while (cont_enum && (wined3d_adapter = wined3d_get_adapter(wined3d, adapter_idx)))
70
    {
71
        char device_name[512] = "", description[512] = "";
72 73 74 75

        /* 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));
76 77
        adapter_id.description = description;
        adapter_id.description_size = sizeof(description);
78

79
        wined3d_mutex_lock();
80
        if (FAILED(hr = wined3d_adapter_get_identifier(wined3d_adapter, 0x0, &adapter_id)))
81
        {
82
            WARN("Failed to get adapter identifier, hr %#lx.\n", hr);
83 84 85
            wined3d_mutex_unlock();
            break;
        }
86
        wined3d_mutex_unlock();
87

88 89
        for (output_idx = 0; cont_enum && (wined3d_output = wined3d_adapter_get_output(
                wined3d_adapter, output_idx)); ++output_idx)
90
        {
91
            wined3d_mutex_lock();
92
            if (FAILED(hr = wined3d_output_get_desc(wined3d_output, &output_desc)))
93
            {
94
                WARN("Failed to get output description, hr %#lx.\n", hr);
95 96 97 98 99 100 101
                wined3d_mutex_unlock();
                break;
            }
            wined3d_mutex_unlock();

            TRACE("Interface %u: %s\n", interface_count++,
                    wine_dbgstr_guid(&adapter_id.device_identifier));
102 103
            WideCharToMultiByte(CP_ACP, 0, output_desc.device_name, -1, device_name,
                    sizeof(device_name), NULL, NULL);
104
            cont_enum = callback(&adapter_id.device_identifier, adapter_id.description,
105
                    device_name, context, output_desc.monitor);
106
        }
107 108 109 110 111

        if (FAILED(hr))
            break;

        ++adapter_idx;
112 113 114
    }
}

115 116 117
/* Handle table functions */
BOOL ddraw_handle_table_init(struct ddraw_handle_table *t, UINT initial_size)
{
118
    if (!(t->entries = heap_alloc_zero(initial_size * sizeof(*t->entries))))
119 120 121 122 123 124 125 126 127 128 129 130 131
    {
        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)
{
132
    heap_free(t->entries);
133 134 135 136 137 138 139 140 141 142 143 144 145 146
    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)
        {
147
            ERR("Handle %#lx (%p) is in the free list, but has type %#x.\n", idx, entry->object, entry->type);
148 149 150 151 152 153 154 155 156 157 158 159 160
            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);
161 162 163
        struct ddraw_handle_entry *new_entries;

        if (!(new_entries = heap_realloc(t->entries, new_size * sizeof(*t->entries))))
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
        {
            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)
    {
186
        WARN("Invalid handle %#lx passed.\n", handle);
187 188 189 190 191 192
        return NULL;
    }

    entry = &t->entries[handle];
    if (entry->type != type)
    {
193
        WARN("Handle %#lx (%p) is not of type %#x.\n", handle, entry->object, type);
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
        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)
    {
211
        WARN("Invalid handle %#lx passed.\n", handle);
212 213 214 215 216 217
        return NULL;
    }

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

    return entry->object;
}

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
HRESULT WINAPI GetSurfaceFromDC(HDC dc, IDirectDrawSurface4 **surface, HDC *device_dc)
{
    struct ddraw *ddraw;

    TRACE("dc %p, surface %p, device_dc %p.\n", dc, surface, device_dc);

    if (!surface)
        return E_INVALIDARG;

    if (!device_dc)
    {
        *surface = NULL;

        return E_INVALIDARG;
    }

    wined3d_mutex_lock();
    LIST_FOR_EACH_ENTRY(ddraw, &global_ddraw_list, struct ddraw, ddraw_list_entry)
    {
        if (FAILED(IDirectDraw4_GetSurfaceFromDC(&ddraw->IDirectDraw4_iface, dc, surface)))
            continue;

        *device_dc = NULL; /* FIXME */
        wined3d_mutex_unlock();
        return DD_OK;
    }
    wined3d_mutex_unlock();

    *surface = NULL;
    *device_dc = NULL;

    return DDERR_NOTFOUND;
}

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
/***********************************************************************
 *
 * 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:
277
 *  DD_OK if the Interface was created successfully
278 279 280 281
 *  CLASS_E_NOAGGREGATION if UnkOuter is not NULL
 *  E_OUTOFMEMORY if some allocation failed
 *
 ***********************************************************************/
282
static HRESULT DDRAW_Create(const GUID *guid, void **out, IUnknown *outer_unknown, REFIID iid)
283
{
284
    enum wined3d_device_type device_type;
285
    struct ddraw *ddraw;
286
    DWORD flags = 0;
287
    HRESULT hr;
288

289
    TRACE("driver_guid %s, ddraw %p, outer_unknown %p, interface_iid %s.\n",
290
            debugstr_guid(guid), out, outer_unknown, debugstr_guid(iid));
291

292
    *out = NULL;
293

294 295
    if (guid == (GUID *) DDCREATE_EMULATIONONLY)
    {
296
        device_type = WINED3D_DEVICE_TYPE_REF;
297
    }
298
    else if (guid == (GUID *) DDCREATE_HARDWAREONLY)
299
    {
300
        device_type = WINED3D_DEVICE_TYPE_HAL;
301
    }
302 303
    else
    {
304
        device_type = WINED3D_DEVICE_TYPE_HAL;
305 306
    }

307
    /* DDraw doesn't support aggregation, according to msdn */
308
    if (outer_unknown != NULL)
309
        return CLASS_E_NOAGGREGATION;
310

311 312 313
    if (!IsEqualGUID(iid, &IID_IDirectDraw7))
        flags = WINED3D_LEGACY_FFP_LIGHTING;

314
    if (!(ddraw = heap_alloc_zero(sizeof(*ddraw))))
315
    {
316
        ERR("Out of memory when creating DirectDraw.\n");
317
        return E_OUTOFMEMORY;
318
    }
319

320
    if (FAILED(hr = ddraw_init(ddraw, flags, device_type)))
321
    {
322
        WARN("Failed to initialize ddraw object, hr %#lx.\n", hr);
323
        heap_free(ddraw);
324
        return hr;
325 326
    }

327
    hr = IDirectDraw7_QueryInterface(&ddraw->IDirectDraw7_iface, iid, out);
328 329 330 331 332
    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);
333

334
    return hr;
335 336 337
}

/***********************************************************************
338 339 340 341 342 343 344 345
 * DirectDrawCreate (DDRAW.@)
 *
 * Creates legacy DirectDraw Interfaces. Can't create IDirectDraw7
 * interfaces in theory
 *
 * Arguments, return values: See DDRAW_Create
 *
 ***********************************************************************/
346
HRESULT WINAPI DECLSPEC_HOTPATCH DirectDrawCreate(GUID *driver_guid, IDirectDraw **ddraw, IUnknown *outer)
347
{
348
    HRESULT hr;
349

350 351
    TRACE("driver_guid %s, ddraw %p, outer %p.\n",
            debugstr_guid(driver_guid), ddraw, outer);
352

353
    wined3d_mutex_lock();
354
    hr = DDRAW_Create(driver_guid, (void **)ddraw, outer, &IID_IDirectDraw);
355
    wined3d_mutex_unlock();
356 357 358

    if (SUCCEEDED(hr))
    {
359 360
        if (FAILED(hr = IDirectDraw_Initialize(*ddraw, driver_guid)))
            IDirectDraw_Release(*ddraw);
361 362
    }

363
    return hr;
364 365 366
}

/***********************************************************************
367 368 369 370 371 372 373 374
 * DirectDrawCreateEx (DDRAW.@)
 *
 * Only creates new IDirectDraw7 interfaces, supposed to fail if legacy
 * interfaces are requested.
 *
 * Arguments, return values: See DDRAW_Create
 *
 ***********************************************************************/
Henri Verbeet's avatar
Henri Verbeet committed
375 376
HRESULT WINAPI DECLSPEC_HOTPATCH DirectDrawCreateEx(GUID *driver_guid,
        void **ddraw, REFIID interface_iid, IUnknown *outer)
377
{
378
    HRESULT hr;
379

Henri Verbeet's avatar
Henri Verbeet committed
380 381
    TRACE("driver_guid %s, ddraw %p, interface_iid %s, outer %p.\n",
            debugstr_guid(driver_guid), ddraw, debugstr_guid(interface_iid), outer);
382

Henri Verbeet's avatar
Henri Verbeet committed
383
    if (!IsEqualGUID(interface_iid, &IID_IDirectDraw7))
384
        return DDERR_INVALIDPARAMS;
385

386
    wined3d_mutex_lock();
Henri Verbeet's avatar
Henri Verbeet committed
387
    hr = DDRAW_Create(driver_guid, ddraw, outer, interface_iid);
388
    wined3d_mutex_unlock();
389 390 391

    if (SUCCEEDED(hr))
    {
Henri Verbeet's avatar
Henri Verbeet committed
392 393
        IDirectDraw7 *ddraw7 = *(IDirectDraw7 **)ddraw;
        hr = IDirectDraw7_Initialize(ddraw7, driver_guid);
394 395 396 397
        if (FAILED(hr))
            IDirectDraw7_Release(ddraw7);
    }

398
    return hr;
399 400
}

401
/***********************************************************************
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
 * 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
 *
 *
 ***********************************************************************/
421
HRESULT WINAPI DirectDrawEnumerateA(LPDDENUMCALLBACKA callback, void *context)
422
{
423
    struct callback_info info;
424

425
    TRACE("callback %p, context %p.\n", callback, context);
426

427 428 429
    info.callback = callback;
    info.context = context;
    return DirectDrawEnumerateExA(enum_callback, &info, 0x0);
430
}
431

432 433 434 435 436 437 438 439 440
/***********************************************************************
 * DirectDrawEnumerateExA (DDRAW.@)
 *
 * Enumerates DirectDraw7 drivers, ascii version. See
 * the comments above DirectDrawEnumerateA for more details.
 *
 * The Flag member is not supported right now.
 *
 ***********************************************************************/
441
HRESULT WINAPI DirectDrawEnumerateExA(LPDDENUMCALLBACKEXA callback, void *context, DWORD flags)
442
{
443 444
    struct wined3d *wined3d;

445
    TRACE("callback %p, context %p, flags %#lx.\n", callback, context, flags);
446

447
    if (flags & ~(DDENUM_ATTACHEDSECONDARYDEVICES |
448 449 450 451
                  DDENUM_DETACHEDSECONDARYDEVICES |
                  DDENUM_NONDISPLAYDEVICES))
        return DDERR_INVALIDPARAMS;

452
    if (flags & ~DDENUM_ATTACHEDSECONDARYDEVICES)
453
        FIXME("flags %#lx not handled\n", flags & ~DDENUM_ATTACHEDSECONDARYDEVICES);
454

455
    TRACE("Enumerating ddraw interfaces\n");
456
    if (!(wined3d = wined3d_create(DDRAW_WINED3D_FLAGS)))
457
    {
458
        if (!(wined3d = wined3d_create(DDRAW_WINED3D_FLAGS | WINED3D_NO3D)))
459 460 461 462 463 464 465
        {
            WARN("Failed to create a wined3d object.\n");
            return E_FAIL;
        }

        WARN("Created a wined3d object without 3D support.\n");
    }
466

467
    __TRY
468
    {
469
        /* QuickTime expects the description "DirectDraw HAL" */
470 471
        static CHAR driver_desc[] = "DirectDraw HAL",
        driver_name[] = "display";
472 473 474 475
        BOOL cont_enum;

        TRACE("Default interface: DirectDraw HAL\n");
        cont_enum = callback(NULL, driver_desc, driver_name, context, 0);
476 477

        /* The Battle.net System Checker expects both a NULL device and a GUID-based device */
478
        if (cont_enum && (flags & DDENUM_ATTACHEDSECONDARYDEVICES))
479
            ddraw_enumerate_secondary_devices(wined3d, callback, context);
480
    }
481 482
    __EXCEPT_PAGE_FAULT
    {
483
        wined3d_decref(wined3d);
484
        return DDERR_INVALIDPARAMS;
485 486
    }
    __ENDTRY;
487

488
    wined3d_decref(wined3d);
489 490
    TRACE("End of enumeration\n");
    return DD_OK;
491 492
}

493
/***********************************************************************
494
 * DirectDrawEnumerateW (DDRAW.@)
495
 *
496 497
 * Enumerates legacy drivers, unicode version.
 * This function is not implemented on Windows.
498 499
 *
 ***********************************************************************/
500
HRESULT WINAPI DirectDrawEnumerateW(LPDDENUMCALLBACKW callback, void *context)
501
{
502
    TRACE("callback %p, context %p.\n", callback, context);
503

504
    if (!callback)
505 506 507 508
        return DDERR_INVALIDPARAMS;
    else
        return DDERR_UNSUPPORTED;
}
509

510
/***********************************************************************
511
 * DirectDrawEnumerateExW (DDRAW.@)
512
 *
513 514
 * Enumerates DirectDraw7 drivers, unicode version.
 * This function is not implemented on Windows.
515 516
 *
 ***********************************************************************/
517
HRESULT WINAPI DirectDrawEnumerateExW(LPDDENUMCALLBACKEXW callback, void *context, DWORD flags)
518
{
519
    TRACE("callback %p, context %p, flags %#lx.\n", callback, context, flags);
520 521 522

    return DDERR_UNSUPPORTED;
}
523

524 525 526
/***********************************************************************
 * Classfactory implementation.
 ***********************************************************************/
527

528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
/***********************************************************************
 * 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)
545 546 547
{
    HRESULT hr;

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

550
    wined3d_mutex_lock();
551
    hr = DDRAW_Create(NULL, obj, UnkOuter, iid);
552 553
    wined3d_mutex_unlock();

554
    return hr;
555 556
}

557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
/***********************************************************************
 * 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)
574
{
575 576 577
    HRESULT hr;
    IDirectDrawClipper *Clip;

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

580
    wined3d_mutex_lock();
581
    hr = DirectDrawCreateClipper(0, &Clip, UnkOuter);
582 583
    if (hr != DD_OK)
    {
584
        wined3d_mutex_unlock();
585 586
        return hr;
    }
587

588 589
    hr = IDirectDrawClipper_QueryInterface(Clip, riid, obj);
    IDirectDrawClipper_Release(Clip);
590

591 592
    wined3d_mutex_unlock();

593 594
    return hr;
}
595 596 597

static const struct object_creation_info object_creation[] =
{
598 599 600
    { &CLSID_DirectDraw,        CF_CreateDirectDraw },
    { &CLSID_DirectDraw7,       CF_CreateDirectDraw },
    { &CLSID_DirectDrawClipper, CF_CreateDirectDrawClipper }
601 602
};

603
struct ddraw_class_factory
604 605 606 607
{
    IClassFactory IClassFactory_iface;

    LONG ref;
Henri Verbeet's avatar
Henri Verbeet committed
608
    HRESULT (*pfnCreateInstance)(IUnknown *outer, REFIID iid, void **out);
609
};
610

611
static inline struct ddraw_class_factory *impl_from_IClassFactory(IClassFactory *iface)
612
{
613
    return CONTAINING_RECORD(iface, struct ddraw_class_factory, IClassFactory_iface);
614 615
}

616 617 618 619 620 621 622 623 624 625 626 627 628 629
/*******************************************************************************
 * 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
 *
 *******************************************************************************/
630
static HRESULT WINAPI ddraw_class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
631
{
632
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
633

634
    if (IsEqualGUID(riid, &IID_IUnknown)
635
        || IsEqualGUID(riid, &IID_IClassFactory))
636
    {
637
        IClassFactory_AddRef(iface);
638
        *out = iface;
639
        return S_OK;
640 641
    }

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

644 645 646
    return E_NOINTERFACE;
}

647 648 649 650 651 652 653 654 655
/*******************************************************************************
 * IDirectDrawClassFactory::AddRef
 *
 * AddRef for the class factory
 *
 * RETURNS
 *  The new refcount
 *
 *******************************************************************************/
656
static ULONG WINAPI ddraw_class_factory_AddRef(IClassFactory *iface)
657
{
658 659
    struct ddraw_class_factory *factory = impl_from_IClassFactory(iface);
    ULONG ref = InterlockedIncrement(&factory->ref);
660

661
    TRACE("%p increasing refcount to %lu.\n", factory, ref);
662

663
    return ref;
664 665
}

666 667 668 669 670 671 672 673 674 675
/*******************************************************************************
 * IDirectDrawClassFactory::Release
 *
 * Release for the class factory. If the refcount falls to 0, the object
 * is destroyed
 *
 * RETURNS
 *  The new refcount
 *
 *******************************************************************************/
676
static ULONG WINAPI ddraw_class_factory_Release(IClassFactory *iface)
677
{
678 679
    struct ddraw_class_factory *factory = impl_from_IClassFactory(iface);
    ULONG ref = InterlockedDecrement(&factory->ref);
680

681
    TRACE("%p decreasing refcount to %lu.\n", factory, ref);
682

683
    if (!ref)
684
        heap_free(factory);
685

686
    return ref;
687 688
}

689

690 691 692 693 694 695
/*******************************************************************************
 * IDirectDrawClassFactory::CreateInstance
 *
 * What is this? Seems to create DirectDraw objects...
 *
 * Params
Austin English's avatar
Austin English committed
696
 *  The usual things???
697 698 699 700 701
 *
 * RETURNS
 *  ???
 *
 *******************************************************************************/
702 703
static HRESULT WINAPI ddraw_class_factory_CreateInstance(IClassFactory *iface,
        IUnknown *outer_unknown, REFIID riid, void **out)
704
{
705
    struct ddraw_class_factory *factory = impl_from_IClassFactory(iface);
706

707 708
    TRACE("iface %p, outer_unknown %p, riid %s, out %p.\n",
            iface, outer_unknown, debugstr_guid(riid), out);
709

710
    return factory->pfnCreateInstance(outer_unknown, riid, out);
711 712
}

713 714 715 716 717 718 719 720 721 722 723 724
/*******************************************************************************
 * IDirectDrawClassFactory::LockServer
 *
 * What is this?
 *
 * Params
 *  ???
 *
 * RETURNS
 *  S_OK, because it's a stub
 *
 *******************************************************************************/
725
static HRESULT WINAPI ddraw_class_factory_LockServer(IClassFactory *iface, BOOL dolock)
726
{
727 728
    FIXME("iface %p, dolock %#x stub!\n", iface, dolock);

729 730 731
    return S_OK;
}

732 733 734 735
/*******************************************************************************
 * The class factory VTable
 *******************************************************************************/
static const IClassFactoryVtbl IClassFactory_Vtbl =
736
{
737 738 739 740 741
    ddraw_class_factory_QueryInterface,
    ddraw_class_factory_AddRef,
    ddraw_class_factory_Release,
    ddraw_class_factory_CreateInstance,
    ddraw_class_factory_LockServer
742 743
};

Henri Verbeet's avatar
Henri Verbeet committed
744
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **out)
745
{
746
    struct ddraw_class_factory *factory;
747
    unsigned int i;
748

Henri Verbeet's avatar
Henri Verbeet committed
749 750
    TRACE("rclsid %s, riid %s, out %p.\n",
            debugstr_guid(rclsid), debugstr_guid(riid), out);
751

752 753 754
    if (!IsEqualGUID(&IID_IClassFactory, riid)
            && !IsEqualGUID(&IID_IUnknown, riid))
        return E_NOINTERFACE;
755

756
    for (i=0; i < ARRAY_SIZE(object_creation); i++)
757
    {
758 759
        if (IsEqualGUID(object_creation[i].clsid, rclsid))
            break;
760 761
    }

762
    if (i == ARRAY_SIZE(object_creation))
763
    {
764 765
        FIXME("%s: no class found.\n", debugstr_guid(rclsid));
        return CLASS_E_CLASSNOTAVAILABLE;
766
    }
767

768 769
    if (!(factory = heap_alloc_zero(sizeof(*factory))))
        return E_OUTOFMEMORY;
770

771
    factory->IClassFactory_iface.lpVtbl = &IClassFactory_Vtbl;
772 773 774 775
    factory->ref = 1;

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

Henri Verbeet's avatar
Henri Verbeet committed
776
    *out = factory;
777
    return S_OK;
778 779 780
}


781 782 783 784 785 786 787 788
/***********************************************************************
 * 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, ...)
 *
 ***********************************************************************/
Henri Verbeet's avatar
Henri Verbeet committed
789
BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved)
790
{
791 792 793
    switch (reason)
    {
    case DLL_PROCESS_ATTACH:
794
    {
795
        static HMODULE ddraw_self;
796
        HKEY hkey = 0;
797
        WNDCLASSA wc;
798

799 800 801 802 803 804 805
        /* 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;
Henri Verbeet's avatar
Henri Verbeet committed
806
        wc.hInstance = inst;
807 808 809 810 811 812 813
        wc.hIcon = 0;
        wc.hCursor = 0;
        wc.hbrBackground = GetStockObject(BLACK_BRUSH);
        wc.lpszMenuName = NULL;
        wc.lpszClassName = DDRAW_WINDOW_CLASS_NAME;
        if (!RegisterClassA(&wc))
        {
814
            ERR("Failed to register ddraw window class, last error %#lx.\n", GetLastError());
815 816 817
            return FALSE;
        }

818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
        /* 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 ) )
        {
840 841
            DWORD type, data, size;

842
            size = sizeof(data);
Henri Verbeet's avatar
Henri Verbeet committed
843
            if (!RegQueryValueExA(hkey, "ForceRefreshRate", NULL, &type, (BYTE *)&data, &size) && type == REG_DWORD)
844
            {
845
                TRACE("ForceRefreshRate set; overriding refresh rate to %ld Hz\n", data);
846 847 848 849 850
                force_refresh_rate = data;
            }
            RegCloseKey( hkey );
        }

851 852 853 854
        /* 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
855 856 857
         * this is supposed to work on Windows. */
        if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN,
                (const WCHAR *)&ddraw_self, &ddraw_self))
858 859
            ERR("Failed to get own module handle.\n");

Henri Verbeet's avatar
Henri Verbeet committed
860 861
        instance = inst;
        DisableThreadLibraryCalls(inst);
862
        break;
863
    }
864 865

    case DLL_PROCESS_DETACH:
866
        if (WARN_ON(ddraw))
867
        {
868
            struct ddraw *ddraw;
869

870
            LIST_FOR_EACH_ENTRY(ddraw, &global_ddraw_list, struct ddraw, ddraw_list_entry)
871
            {
872
                struct ddraw_surface *surface;
873

874
                WARN("DirectDraw object %p has reference counts {%lu, %lu, %lu, %lu, %lu}.\n",
875
                        ddraw, ddraw->ref7, ddraw->ref4, ddraw->ref3, ddraw->ref2, ddraw->ref1);
876

877 878
                if (ddraw->d3ddevice)
                    WARN("DirectDraw object %p has Direct3D device %p attached.\n", ddraw, ddraw->d3ddevice);
879

880 881
                LIST_FOR_EACH_ENTRY(surface, &ddraw->surface_list, struct ddraw_surface, surface_list_entry)
                {
882
                    WARN("Surface %p has reference counts {%lu, %lu, %lu, %lu, %lu, %lu}.\n",
883 884 885
                            surface, surface->ref7, surface->ref4, surface->ref3,
                            surface->ref2, surface->ref1, surface->gamma_count);
                }
886
            }
887
        }
888

889
        if (reserved) break;
Henri Verbeet's avatar
Henri Verbeet committed
890
        UnregisterClassA(DDRAW_WINDOW_CLASS_NAME, inst);
891
    }
892 893 894

    return TRUE;
}