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 library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * 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 #include "config.h" 25 #include "wine/port.h" 26 27 #define DDRAW_INIT_GUID 28 #include "ddraw_private.h" 29 #include "rpcproxy.h" 30 31 #include "wine/exception.h" 32 #include "winreg.h" 33 34 WINE_DEFAULT_DEBUG_CHANNEL(ddraw); 35 36 static struct list global_ddraw_list = LIST_INIT(global_ddraw_list); 37 38 static HINSTANCE instance; 39 40 /* value of ForceRefreshRate */ 41 DWORD force_refresh_rate = 0; 42 43 /* Structure for converting DirectDrawEnumerateA to DirectDrawEnumerateExA */ 44 struct callback_info 45 { 46 LPDDENUMCALLBACKA callback; 47 void *context; 48 }; 49 50 /* Enumeration callback for converting DirectDrawEnumerateA to DirectDrawEnumerateExA */ 51 static BOOL CALLBACK enum_callback(GUID *guid, char *description, char *driver_name, 52 void *context, HMONITOR monitor) 53 { 54 const struct callback_info *info = context; 55 56 return info->callback(guid, description, driver_name, info->context); 57 } 58 59 static void ddraw_enumerate_secondary_devices(struct wined3d *wined3d, LPDDENUMCALLBACKEXA callback, 60 void *context) 61 { 62 struct wined3d_adapter_identifier adapter_id; 63 struct wined3d_output_desc output_desc; 64 BOOL cont_enum = TRUE; 65 HRESULT hr = S_OK; 66 UINT adapter = 0; 67 68 for (adapter = 0; SUCCEEDED(hr) && cont_enum; adapter++) 69 { 70 char DriverName[512] = "", DriverDescription[512] = ""; 71 72 /* The Battle.net System Checker expects the GetAdapterIdentifier DeviceName to match the 73 * Driver Name, so obtain the DeviceName and GUID from D3D. */ 74 memset(&adapter_id, 0x0, sizeof(adapter_id)); 75 adapter_id.device_name = DriverName; 76 adapter_id.device_name_size = sizeof(DriverName); 77 adapter_id.description = DriverDescription; 78 adapter_id.description_size = sizeof(DriverDescription); 79 wined3d_mutex_lock(); 80 if (SUCCEEDED(hr = wined3d_get_adapter_identifier(wined3d, adapter, 0x0, &adapter_id))) 81 hr = wined3d_get_output_desc(wined3d, adapter, &output_desc); 82 wined3d_mutex_unlock(); 83 if (SUCCEEDED(hr)) 84 { 85 TRACE("Interface %d: %s\n", adapter, wine_dbgstr_guid(&adapter_id.device_identifier)); 86 cont_enum = callback(&adapter_id.device_identifier, adapter_id.description, 87 adapter_id.device_name, context, output_desc.monitor); 88 } 89 } 90 } 91 92 /* Handle table functions */ 93 BOOL ddraw_handle_table_init(struct ddraw_handle_table *t, UINT initial_size) 94 { 95 if (!(t->entries = heap_alloc_zero(initial_size * sizeof(*t->entries)))) 96 { 97 ERR("Failed to allocate handle table memory.\n"); 98 return FALSE; 99 } 100 t->free_entries = NULL; 101 t->table_size = initial_size; 102 t->entry_count = 0; 103 104 return TRUE; 105 } 106 107 void ddraw_handle_table_destroy(struct ddraw_handle_table *t) 108 { 109 heap_free(t->entries); 110 memset(t, 0, sizeof(*t)); 111 } 112 113 DWORD ddraw_allocate_handle(struct ddraw_handle_table *t, void *object, enum ddraw_handle_type type) 114 { 115 struct ddraw_handle_entry *entry; 116 117 if (t->free_entries) 118 { 119 DWORD idx = t->free_entries - t->entries; 120 /* Use a free handle */ 121 entry = t->free_entries; 122 if (entry->type != DDRAW_HANDLE_FREE) 123 { 124 ERR("Handle %#x (%p) is in the free list, but has type %#x.\n", idx, entry->object, entry->type); 125 return DDRAW_INVALID_HANDLE; 126 } 127 t->free_entries = entry->object; 128 entry->object = object; 129 entry->type = type; 130 131 return idx; 132 } 133 134 if (!(t->entry_count < t->table_size)) 135 { 136 /* Grow the table */ 137 UINT new_size = t->table_size + (t->table_size >> 1); 138 struct ddraw_handle_entry *new_entries; 139 140 if (!(new_entries = heap_realloc(t->entries, new_size * sizeof(*t->entries)))) 141 { 142 ERR("Failed to grow the handle table.\n"); 143 return DDRAW_INVALID_HANDLE; 144 } 145 t->entries = new_entries; 146 t->table_size = new_size; 147 } 148 149 entry = &t->entries[t->entry_count]; 150 entry->object = object; 151 entry->type = type; 152 153 return t->entry_count++; 154 } 155 156 void *ddraw_free_handle(struct ddraw_handle_table *t, DWORD handle, enum ddraw_handle_type type) 157 { 158 struct ddraw_handle_entry *entry; 159 void *object; 160 161 if (handle == DDRAW_INVALID_HANDLE || handle >= t->entry_count) 162 { 163 WARN("Invalid handle %#x passed.\n", handle); 164 return NULL; 165 } 166 167 entry = &t->entries[handle]; 168 if (entry->type != type) 169 { 170 WARN("Handle %#x (%p) is not of type %#x.\n", handle, entry->object, type); 171 return NULL; 172 } 173 174 object = entry->object; 175 entry->object = t->free_entries; 176 entry->type = DDRAW_HANDLE_FREE; 177 t->free_entries = entry; 178 179 return object; 180 } 181 182 void *ddraw_get_object(struct ddraw_handle_table *t, DWORD handle, enum ddraw_handle_type type) 183 { 184 struct ddraw_handle_entry *entry; 185 186 if (handle == DDRAW_INVALID_HANDLE || handle >= t->entry_count) 187 { 188 WARN("Invalid handle %#x passed.\n", handle); 189 return NULL; 190 } 191 192 entry = &t->entries[handle]; 193 if (entry->type != type) 194 { 195 WARN("Handle %#x (%p) is not of type %#x.\n", handle, entry->object, type); 196 return NULL; 197 } 198 199 return entry->object; 200 } 201 202 HRESULT WINAPI GetSurfaceFromDC(HDC dc, IDirectDrawSurface4 **surface, HDC *device_dc) 203 { 204 struct ddraw *ddraw; 205 206 TRACE("dc %p, surface %p, device_dc %p.\n", dc, surface, device_dc); 207 208 if (!surface) 209 return E_INVALIDARG; 210 211 if (!device_dc) 212 { 213 *surface = NULL; 214 215 return E_INVALIDARG; 216 } 217 218 wined3d_mutex_lock(); 219 LIST_FOR_EACH_ENTRY(ddraw, &global_ddraw_list, struct ddraw, ddraw_list_entry) 220 { 221 if (FAILED(IDirectDraw4_GetSurfaceFromDC(&ddraw->IDirectDraw4_iface, dc, surface))) 222 continue; 223 224 *device_dc = NULL; /* FIXME */ 225 wined3d_mutex_unlock(); 226 return DD_OK; 227 } 228 wined3d_mutex_unlock(); 229 230 *surface = NULL; 231 *device_dc = NULL; 232 233 return DDERR_NOTFOUND; 234 } 235 236 /*********************************************************************** 237 * 238 * Helper function for DirectDrawCreate and friends 239 * Creates a new DDraw interface with the given REFIID 240 * 241 * Interfaces that can be created: 242 * IDirectDraw, IDirectDraw2, IDirectDraw4, IDirectDraw7 243 * IDirect3D, IDirect3D2, IDirect3D3, IDirect3D7. (Does Windows return 244 * IDirect3D interfaces?) 245 * 246 * Arguments: 247 * guid: ID of the requested driver, NULL for the default driver. 248 * The GUID can be queried with DirectDrawEnumerate(Ex)A/W 249 * DD: Used to return the pointer to the created object 250 * UnkOuter: For aggregation, which is unsupported. Must be NULL 251 * iid: requested version ID. 252 * 253 * Returns: 254 * DD_OK if the Interface was created successfully 255 * CLASS_E_NOAGGREGATION if UnkOuter is not NULL 256 * E_OUTOFMEMORY if some allocation failed 257 * 258 ***********************************************************************/ 259 static HRESULT 260 DDRAW_Create(const GUID *guid, 261 void **DD, 262 IUnknown *UnkOuter, 263 REFIID iid) 264 { 265 enum wined3d_device_type device_type; 266 struct ddraw *ddraw; 267 HRESULT hr; 268 DWORD flags = 0; 269 270 TRACE("driver_guid %s, ddraw %p, outer_unknown %p, interface_iid %s.\n", 271 debugstr_guid(guid), DD, UnkOuter, debugstr_guid(iid)); 272 273 *DD = NULL; 274 275 if (guid == (GUID *) DDCREATE_EMULATIONONLY) 276 { 277 /* Use the reference device id. This doesn't actually change anything, 278 * WineD3D always uses OpenGL for D3D rendering. One could make it request 279 * indirect rendering 280 */ 281 device_type = WINED3D_DEVICE_TYPE_REF; 282 } 283 else if(guid == (GUID *) DDCREATE_HARDWAREONLY) 284 { 285 device_type = WINED3D_DEVICE_TYPE_HAL; 286 } 287 else 288 { 289 device_type = 0; 290 } 291 292 /* DDraw doesn't support aggregation, according to msdn */ 293 if (UnkOuter != NULL) 294 return CLASS_E_NOAGGREGATION; 295 296 if (!IsEqualGUID(iid, &IID_IDirectDraw7)) 297 flags = WINED3D_LEGACY_FFP_LIGHTING; 298 299 /* DirectDraw creation comes here */ 300 if (!(ddraw = heap_alloc_zero(sizeof(*ddraw)))) 301 { 302 ERR("Out of memory when creating DirectDraw\n"); 303 return E_OUTOFMEMORY; 304 } 305 306 hr = ddraw_init(ddraw, flags, device_type); 307 if (FAILED(hr)) 308 { 309 WARN("Failed to initialize ddraw object, hr %#x.\n", hr); 310 heap_free(ddraw); 311 return hr; 312 } 313 314 hr = IDirectDraw7_QueryInterface(&ddraw->IDirectDraw7_iface, iid, DD); 315 IDirectDraw7_Release(&ddraw->IDirectDraw7_iface); 316 if (SUCCEEDED(hr)) 317 list_add_head(&global_ddraw_list, &ddraw->ddraw_list_entry); 318 else 319 WARN("Failed to query interface %s from ddraw object %p.\n", debugstr_guid(iid), ddraw); 320 321 return hr; 322 } 323 324 /*********************************************************************** 325 * DirectDrawCreate (DDRAW.@) 326 * 327 * Creates legacy DirectDraw Interfaces. Can't create IDirectDraw7 328 * interfaces in theory 329 * 330 * Arguments, return values: See DDRAW_Create 331 * 332 ***********************************************************************/ 333 HRESULT WINAPI DECLSPEC_HOTPATCH DirectDrawCreate(GUID *driver_guid, IDirectDraw **ddraw, IUnknown *outer) 334 { 335 HRESULT hr; 336 337 TRACE("driver_guid %s, ddraw %p, outer %p.\n", 338 debugstr_guid(driver_guid), ddraw, outer); 339 340 wined3d_mutex_lock(); 341 hr = DDRAW_Create(driver_guid, (void **)ddraw, outer, &IID_IDirectDraw); 342 wined3d_mutex_unlock(); 343 344 if (SUCCEEDED(hr)) 345 { 346 if (FAILED(hr = IDirectDraw_Initialize(*ddraw, driver_guid))) 347 IDirectDraw_Release(*ddraw); 348 } 349 350 return hr; 351 } 352 353 /*********************************************************************** 354 * DirectDrawCreateEx (DDRAW.@) 355 * 356 * Only creates new IDirectDraw7 interfaces, supposed to fail if legacy 357 * interfaces are requested. 358 * 359 * Arguments, return values: See DDRAW_Create 360 * 361 ***********************************************************************/ 362 HRESULT WINAPI DECLSPEC_HOTPATCH DirectDrawCreateEx(GUID *driver_guid, 363 void **ddraw, REFIID interface_iid, IUnknown *outer) 364 { 365 HRESULT hr; 366 367 TRACE("driver_guid %s, ddraw %p, interface_iid %s, outer %p.\n", 368 debugstr_guid(driver_guid), ddraw, debugstr_guid(interface_iid), outer); 369 370 if (!IsEqualGUID(interface_iid, &IID_IDirectDraw7)) 371 return DDERR_INVALIDPARAMS; 372 373 wined3d_mutex_lock(); 374 hr = DDRAW_Create(driver_guid, ddraw, outer, interface_iid); 375 wined3d_mutex_unlock(); 376 377 if (SUCCEEDED(hr)) 378 { 379 IDirectDraw7 *ddraw7 = *(IDirectDraw7 **)ddraw; 380 hr = IDirectDraw7_Initialize(ddraw7, driver_guid); 381 if (FAILED(hr)) 382 IDirectDraw7_Release(ddraw7); 383 } 384 385 return hr; 386 } 387 388 /*********************************************************************** 389 * DirectDrawEnumerateA (DDRAW.@) 390 * 391 * Enumerates legacy ddraw drivers, ascii version. We only have one 392 * driver, which relays to WineD3D. If we were sufficiently cool, 393 * we could offer various interfaces, which use a different default surface 394 * implementation, but I think it's better to offer this choice in 395 * winecfg, because some apps use the default driver, so we would need 396 * a winecfg option anyway, and there shouldn't be 2 ways to set one setting 397 * 398 * Arguments: 399 * Callback: Callback function from the app 400 * Context: Argument to the call back. 401 * 402 * Returns: 403 * DD_OK on success 404 * E_INVALIDARG if the Callback caused a page fault 405 * 406 * 407 ***********************************************************************/ 408 HRESULT WINAPI DirectDrawEnumerateA(LPDDENUMCALLBACKA callback, void *context) 409 { 410 struct callback_info info; 411 412 TRACE("callback %p, context %p.\n", callback, context); 413 414 info.callback = callback; 415 info.context = context; 416 return DirectDrawEnumerateExA(enum_callback, &info, 0x0); 417 } 418 419 /*********************************************************************** 420 * DirectDrawEnumerateExA (DDRAW.@) 421 * 422 * Enumerates DirectDraw7 drivers, ascii version. See 423 * the comments above DirectDrawEnumerateA for more details. 424 * 425 * The Flag member is not supported right now. 426 * 427 ***********************************************************************/ 428 HRESULT WINAPI DirectDrawEnumerateExA(LPDDENUMCALLBACKEXA callback, void *context, DWORD flags) 429 { 430 struct wined3d *wined3d; 431 432 TRACE("callback %p, context %p, flags %#x.\n", callback, context, flags); 433 434 if (flags & ~(DDENUM_ATTACHEDSECONDARYDEVICES | 435 DDENUM_DETACHEDSECONDARYDEVICES | 436 DDENUM_NONDISPLAYDEVICES)) 437 return DDERR_INVALIDPARAMS; 438 439 if (flags & ~DDENUM_ATTACHEDSECONDARYDEVICES) 440 FIXME("flags 0x%08x not handled\n", flags & ~DDENUM_ATTACHEDSECONDARYDEVICES); 441 442 TRACE("Enumerating ddraw interfaces\n"); 443 if (!(wined3d = wined3d_create(DDRAW_WINED3D_FLAGS))) 444 { 445 if (!(wined3d = wined3d_create(DDRAW_WINED3D_FLAGS | WINED3D_NO3D))) 446 { 447 WARN("Failed to create a wined3d object.\n"); 448 return E_FAIL; 449 } 450 451 WARN("Created a wined3d object without 3D support.\n"); 452 } 453 454 __TRY 455 { 456 /* QuickTime expects the description "DirectDraw HAL" */ 457 static CHAR driver_desc[] = "DirectDraw HAL", 458 driver_name[] = "display"; 459 BOOL cont_enum; 460 461 TRACE("Default interface: DirectDraw HAL\n"); 462 cont_enum = callback(NULL, driver_desc, driver_name, context, 0); 463 464 /* The Battle.net System Checker expects both a NULL device and a GUID-based device */ 465 if (cont_enum && (flags & DDENUM_ATTACHEDSECONDARYDEVICES)) 466 ddraw_enumerate_secondary_devices(wined3d, callback, context); 467 } 468 __EXCEPT_PAGE_FAULT 469 { 470 wined3d_decref(wined3d); 471 return DDERR_INVALIDPARAMS; 472 } 473 __ENDTRY; 474 475 wined3d_decref(wined3d); 476 TRACE("End of enumeration\n"); 477 return DD_OK; 478 } 479 480 /*********************************************************************** 481 * DirectDrawEnumerateW (DDRAW.@) 482 * 483 * Enumerates legacy drivers, unicode version. 484 * This function is not implemented on Windows. 485 * 486 ***********************************************************************/ 487 HRESULT WINAPI DirectDrawEnumerateW(LPDDENUMCALLBACKW callback, void *context) 488 { 489 TRACE("callback %p, context %p.\n", callback, context); 490 491 if (!callback) 492 return DDERR_INVALIDPARAMS; 493 else 494 return DDERR_UNSUPPORTED; 495 } 496 497 /*********************************************************************** 498 * DirectDrawEnumerateExW (DDRAW.@) 499 * 500 * Enumerates DirectDraw7 drivers, unicode version. 501 * This function is not implemented on Windows. 502 * 503 ***********************************************************************/ 504 HRESULT WINAPI DirectDrawEnumerateExW(LPDDENUMCALLBACKEXW callback, void *context, DWORD flags) 505 { 506 TRACE("callback %p, context %p, flags %#x.\n", callback, context, flags); 507 508 return DDERR_UNSUPPORTED; 509 } 510 511 /*********************************************************************** 512 * Classfactory implementation. 513 ***********************************************************************/ 514 515 /*********************************************************************** 516 * CF_CreateDirectDraw 517 * 518 * DDraw creation function for the class factory 519 * 520 * Params: 521 * UnkOuter: Set to NULL 522 * iid: ID of the wanted interface 523 * obj: Address to pass the interface pointer back 524 * 525 * Returns 526 * DD_OK / DDERR*, see DDRAW_Create 527 * 528 ***********************************************************************/ 529 static HRESULT 530 CF_CreateDirectDraw(IUnknown* UnkOuter, REFIID iid, 531 void **obj) 532 { 533 HRESULT hr; 534 535 TRACE("outer_unknown %p, riid %s, object %p.\n", UnkOuter, debugstr_guid(iid), obj); 536 537 wined3d_mutex_lock(); 538 hr = DDRAW_Create(NULL, obj, UnkOuter, iid); 539 wined3d_mutex_unlock(); 540 541 return hr; 542 } 543 544 /*********************************************************************** 545 * CF_CreateDirectDraw 546 * 547 * Clipper creation function for the class factory 548 * 549 * Params: 550 * UnkOuter: Set to NULL 551 * iid: ID of the wanted interface 552 * obj: Address to pass the interface pointer back 553 * 554 * Returns 555 * DD_OK / DDERR*, see DDRAW_Create 556 * 557 ***********************************************************************/ 558 static HRESULT 559 CF_CreateDirectDrawClipper(IUnknown* UnkOuter, REFIID riid, 560 void **obj) 561 { 562 HRESULT hr; 563 IDirectDrawClipper *Clip; 564 565 TRACE("outer_unknown %p, riid %s, object %p.\n", UnkOuter, debugstr_guid(riid), obj); 566 567 wined3d_mutex_lock(); 568 hr = DirectDrawCreateClipper(0, &Clip, UnkOuter); 569 if (hr != DD_OK) 570 { 571 wined3d_mutex_unlock(); 572 return hr; 573 } 574 575 hr = IDirectDrawClipper_QueryInterface(Clip, riid, obj); 576 IDirectDrawClipper_Release(Clip); 577 578 wined3d_mutex_unlock(); 579 580 return hr; 581 } 582 583 static const struct object_creation_info object_creation[] = 584 { 585 { &CLSID_DirectDraw, CF_CreateDirectDraw }, 586 { &CLSID_DirectDraw7, CF_CreateDirectDraw }, 587 { &CLSID_DirectDrawClipper, CF_CreateDirectDrawClipper } 588 }; 589 590 struct ddraw_class_factory 591 { 592 IClassFactory IClassFactory_iface; 593 594 LONG ref; 595 HRESULT (*pfnCreateInstance)(IUnknown *outer, REFIID iid, void **out); 596 }; 597 598 static inline struct ddraw_class_factory *impl_from_IClassFactory(IClassFactory *iface) 599 { 600 return CONTAINING_RECORD(iface, struct ddraw_class_factory, IClassFactory_iface); 601 } 602 603 /******************************************************************************* 604 * IDirectDrawClassFactory::QueryInterface 605 * 606 * QueryInterface for the class factory 607 * 608 * PARAMS 609 * riid Reference to identifier of queried interface 610 * ppv Address to return the interface pointer at 611 * 612 * RETURNS 613 * Success: S_OK 614 * Failure: E_NOINTERFACE 615 * 616 *******************************************************************************/ 617 static HRESULT WINAPI ddraw_class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out) 618 { 619 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out); 620 621 if (IsEqualGUID(riid, &IID_IUnknown) 622 || IsEqualGUID(riid, &IID_IClassFactory)) 623 { 624 IClassFactory_AddRef(iface); 625 *out = iface; 626 return S_OK; 627 } 628 629 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); 630 631 return E_NOINTERFACE; 632 } 633 634 /******************************************************************************* 635 * IDirectDrawClassFactory::AddRef 636 * 637 * AddRef for the class factory 638 * 639 * RETURNS 640 * The new refcount 641 * 642 *******************************************************************************/ 643 static ULONG WINAPI ddraw_class_factory_AddRef(IClassFactory *iface) 644 { 645 struct ddraw_class_factory *factory = impl_from_IClassFactory(iface); 646 ULONG ref = InterlockedIncrement(&factory->ref); 647 648 TRACE("%p increasing refcount to %u.\n", factory, ref); 649 650 return ref; 651 } 652 653 /******************************************************************************* 654 * IDirectDrawClassFactory::Release 655 * 656 * Release for the class factory. If the refcount falls to 0, the object 657 * is destroyed 658 * 659 * RETURNS 660 * The new refcount 661 * 662 *******************************************************************************/ 663 static ULONG WINAPI ddraw_class_factory_Release(IClassFactory *iface) 664 { 665 struct ddraw_class_factory *factory = impl_from_IClassFactory(iface); 666 ULONG ref = InterlockedDecrement(&factory->ref); 667 668 TRACE("%p decreasing refcount to %u.\n", factory, ref); 669 670 if (!ref) 671 heap_free(factory); 672 673 return ref; 674 } 675 676 677 /******************************************************************************* 678 * IDirectDrawClassFactory::CreateInstance 679 * 680 * What is this? Seems to create DirectDraw objects... 681 * 682 * Params 683 * The usual things??? 684 * 685 * RETURNS 686 * ??? 687 * 688 *******************************************************************************/ 689 static HRESULT WINAPI ddraw_class_factory_CreateInstance(IClassFactory *iface, 690 IUnknown *outer_unknown, REFIID riid, void **out) 691 { 692 struct ddraw_class_factory *factory = impl_from_IClassFactory(iface); 693 694 TRACE("iface %p, outer_unknown %p, riid %s, out %p.\n", 695 iface, outer_unknown, debugstr_guid(riid), out); 696 697 return factory->pfnCreateInstance(outer_unknown, riid, out); 698 } 699 700 /******************************************************************************* 701 * IDirectDrawClassFactory::LockServer 702 * 703 * What is this? 704 * 705 * Params 706 * ??? 707 * 708 * RETURNS 709 * S_OK, because it's a stub 710 * 711 *******************************************************************************/ 712 static HRESULT WINAPI ddraw_class_factory_LockServer(IClassFactory *iface, BOOL dolock) 713 { 714 FIXME("iface %p, dolock %#x stub!\n", iface, dolock); 715 716 return S_OK; 717 } 718 719 /******************************************************************************* 720 * The class factory VTable 721 *******************************************************************************/ 722 static const IClassFactoryVtbl IClassFactory_Vtbl = 723 { 724 ddraw_class_factory_QueryInterface, 725 ddraw_class_factory_AddRef, 726 ddraw_class_factory_Release, 727 ddraw_class_factory_CreateInstance, 728 ddraw_class_factory_LockServer 729 }; 730 731 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **out) 732 { 733 struct ddraw_class_factory *factory; 734 unsigned int i; 735 736 TRACE("rclsid %s, riid %s, out %p.\n", 737 debugstr_guid(rclsid), debugstr_guid(riid), out); 738 739 if (!IsEqualGUID(&IID_IClassFactory, riid) 740 && !IsEqualGUID(&IID_IUnknown, riid)) 741 return E_NOINTERFACE; 742 743 for (i=0; i < ARRAY_SIZE(object_creation); i++) 744 { 745 if (IsEqualGUID(object_creation[i].clsid, rclsid)) 746 break; 747 } 748 749 if (i == ARRAY_SIZE(object_creation)) 750 { 751 FIXME("%s: no class found.\n", debugstr_guid(rclsid)); 752 return CLASS_E_CLASSNOTAVAILABLE; 753 } 754 755 if (!(factory = heap_alloc_zero(sizeof(*factory)))) 756 return E_OUTOFMEMORY; 757 758 factory->IClassFactory_iface.lpVtbl = &IClassFactory_Vtbl; 759 factory->ref = 1; 760 761 factory->pfnCreateInstance = object_creation[i].pfnCreateInstance; 762 763 *out = factory; 764 return S_OK; 765 } 766 767 768 /******************************************************************************* 769 * DllCanUnloadNow [DDRAW.@] Determines whether the DLL is in use. 770 * 771 * RETURNS 772 * Success: S_OK 773 * Failure: S_FALSE 774 */ 775 HRESULT WINAPI DllCanUnloadNow(void) 776 { 777 TRACE("\n"); 778 779 return S_FALSE; 780 } 781 782 783 HRESULT WINAPI DllRegisterServer(void) 784 { 785 return __wine_register_resources( instance ); 786 } 787 788 HRESULT WINAPI DllUnregisterServer(void) 789 { 790 return __wine_unregister_resources( instance ); 791 } 792 793 /*********************************************************************** 794 * DllMain (DDRAW.0) 795 * 796 * Could be used to register DirectDraw drivers, if we have more than 797 * one. Also used to destroy any objects left at unload if the 798 * app didn't release them properly(Gothic 2, Diablo 2, Moto racer, ...) 799 * 800 ***********************************************************************/ 801 BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved) 802 { 803 switch (reason) 804 { 805 case DLL_PROCESS_ATTACH: 806 { 807 static HMODULE ddraw_self; 808 HKEY hkey = 0; 809 WNDCLASSA wc; 810 811 /* Register the window class. This is used to create a hidden window 812 * for D3D rendering, if the application didn't pass one. It can also 813 * be used for creating a device window from SetCooperativeLevel(). */ 814 wc.style = CS_HREDRAW | CS_VREDRAW; 815 wc.lpfnWndProc = DefWindowProcA; 816 wc.cbClsExtra = 0; 817 wc.cbWndExtra = 0; 818 wc.hInstance = inst; 819 wc.hIcon = 0; 820 wc.hCursor = 0; 821 wc.hbrBackground = GetStockObject(BLACK_BRUSH); 822 wc.lpszMenuName = NULL; 823 wc.lpszClassName = DDRAW_WINDOW_CLASS_NAME; 824 if (!RegisterClassA(&wc)) 825 { 826 ERR("Failed to register ddraw window class, last error %#x.\n", GetLastError()); 827 return FALSE; 828 } 829 830 /* On Windows one can force the refresh rate that DirectDraw uses by 831 * setting an override value in dxdiag. This is documented in KB315614 832 * (main article), KB230002, and KB217348. By comparing registry dumps 833 * before and after setting the override, we see that the override value 834 * is stored in HKLM\Software\Microsoft\DirectDraw\ForceRefreshRate as a 835 * DWORD that represents the refresh rate to force. We use this 836 * registry entry to modify the behavior of SetDisplayMode so that Wine 837 * users can override the refresh rate in a Windows-compatible way. 838 * 839 * dxdiag will not accept a refresh rate lower than 40 or higher than 840 * 120 so this value should be within that range. It is, of course, 841 * possible for a user to set the registry entry value directly so that 842 * assumption might not hold. 843 * 844 * There is no current mechanism for setting this value through the Wine 845 * GUI. It would be most appropriate to set this value through a dxdiag 846 * clone, but it may be sufficient to use winecfg. 847 * 848 * TODO: Create a mechanism for setting this value through the Wine GUI. 849 */ 850 if ( !RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectDraw", &hkey ) ) 851 { 852 DWORD type, data, size; 853 854 size = sizeof(data); 855 if (!RegQueryValueExA(hkey, "ForceRefreshRate", NULL, &type, (BYTE *)&data, &size) && type == REG_DWORD) 856 { 857 TRACE("ForceRefreshRate set; overriding refresh rate to %d Hz\n", data); 858 force_refresh_rate = data; 859 } 860 RegCloseKey( hkey ); 861 } 862 863 /* Prevent the ddraw module from being unloaded. When switching to 864 * exclusive mode, we replace the window proc of the ddraw window. If 865 * an application would unload ddraw from the WM_DESTROY handler for 866 * that window, it would return to unmapped memory and die. Apparently 867 * this is supposed to work on Windows. */ 868 869 /* ReactOS r61844: Comment out usage of GET_MODULE_HANDLE_EX_FLAG_PIN because it doesn't work */ 870 if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS /*| GET_MODULE_HANDLE_EX_FLAG_PIN*/, 871 (const WCHAR *)&ddraw_self, &ddraw_self)) 872 ERR("Failed to get own module handle.\n"); 873 874 instance = inst; 875 DisableThreadLibraryCalls(inst); 876 break; 877 } 878 879 case DLL_PROCESS_DETACH: 880 if (WARN_ON(ddraw)) 881 { 882 struct ddraw *ddraw; 883 884 LIST_FOR_EACH_ENTRY(ddraw, &global_ddraw_list, struct ddraw, ddraw_list_entry) 885 { 886 struct ddraw_surface *surface; 887 888 WARN("DirectDraw object %p has reference counts {%u, %u, %u, %u, %u}.\n", 889 ddraw, ddraw->ref7, ddraw->ref4, ddraw->ref3, ddraw->ref2, ddraw->ref1); 890 891 if (ddraw->d3ddevice) 892 WARN("DirectDraw object %p has Direct3D device %p attached.\n", ddraw, ddraw->d3ddevice); 893 894 LIST_FOR_EACH_ENTRY(surface, &ddraw->surface_list, struct ddraw_surface, surface_list_entry) 895 { 896 WARN("Surface %p has reference counts {%u, %u, %u, %u, %u, %u}.\n", 897 surface, surface->ref7, surface->ref4, surface->ref3, 898 surface->ref2, surface->ref1, surface->gamma_count); 899 } 900 } 901 } 902 903 if (reserved) break; 904 UnregisterClassA(DDRAW_WINDOW_CLASS_NAME, inst); 905 } 906 907 return TRUE; 908 } 909