1 /* dplayx.dll global data implementation. 2 * 3 * Copyright 1999,2000 - Peter Hunnisett 4 * 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 * 20 * 21 * NOTES: 22 * o Implementation of all things which are associated with dplay on 23 * the computer - i.e. shared resources and such. Methods in this 24 * compilation unit should not call anything outside of this unit 25 * except base windows services and an interface to start the 26 * messaging thread. 27 * o Methods that begin with DPLAYX_ are used for dealing with 28 * dplayx.dll data which is accessible from all processes. 29 * 30 */ 31 32 #include <stdarg.h> 33 #include <string.h> 34 35 #define NONAMELESSUNION 36 37 #include "wine/debug.h" 38 #include "windef.h" 39 #include "winbase.h" 40 #include "winerror.h" 41 42 #include "wingdi.h" 43 #include "winuser.h" 44 45 #include "dplayx_global.h" 46 #include "dplayx_messages.h" /* For CreateMessageReceptionThread only */ 47 48 WINE_DEFAULT_DEBUG_CHANNEL(dplay); 49 50 /* FIXME: Need to do all that fun other dll referencing type of stuff */ 51 52 /* Static data for all processes */ 53 static const char lpszDplayxSemaName[] = "WINE_DPLAYX_SM"; 54 static HANDLE hDplayxSema; 55 56 static const char lpszDplayxFileMapping[] = "WINE_DPLAYX_FM"; 57 static HANDLE hDplayxSharedMem; 58 59 static LPVOID lpSharedStaticData = NULL; 60 61 62 #define DPLAYX_AcquireSemaphore() TRACE( "Waiting for DPLAYX semaphore\n" ); \ 63 WaitForSingleObject( hDplayxSema, INFINITE );\ 64 TRACE( "Through wait\n" ) 65 66 #define DPLAYX_ReleaseSemaphore() ReleaseSemaphore( hDplayxSema, 1, NULL ); \ 67 TRACE( "DPLAYX Semaphore released\n" ) /* FIXME: Is this correct? */ 68 69 70 /* HACK for simple global data right now */ 71 #define dwStaticSharedSize (128 * 1024) /* 128 KBytes */ 72 #define dwDynamicSharedSize (512 * 1024) /* 512 KBytes */ 73 #define dwTotalSharedSize ( dwStaticSharedSize + dwDynamicSharedSize ) 74 75 76 /* FIXME: Is there no easier way? */ 77 78 /* Pretend the entire dynamic area is carved up into 512 byte blocks. 79 * Each block has 4 bytes which are 0 unless used */ 80 #define dwBlockSize 512 81 #define dwMaxBlock (dwDynamicSharedSize/dwBlockSize) 82 83 typedef struct 84 { 85 BOOL used; 86 BYTE data[dwBlockSize - sizeof(BOOL)]; 87 } DPLAYX_MEM_SLICE; 88 C_ASSERT(sizeof(DPLAYX_MEM_SLICE) == dwBlockSize); 89 90 static DPLAYX_MEM_SLICE* lpMemArea; 91 92 static void DPLAYX_PrivHeapFree( LPVOID addr ) 93 { 94 LPVOID lpAddrStart; 95 DWORD dwBlockUsed; 96 97 /* Handle getting passed a NULL */ 98 if( addr == NULL ) 99 { 100 return; 101 } 102 103 lpAddrStart = CONTAINING_RECORD(addr, DPLAYX_MEM_SLICE, data); /* Find block header */ 104 dwBlockUsed = ((BYTE*)lpAddrStart - (BYTE*)lpMemArea)/dwBlockSize; 105 106 lpMemArea[ dwBlockUsed ].used = FALSE; 107 } 108 109 static LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size ) 110 { 111 LPVOID lpvArea = NULL; 112 UINT uBlockUsed; 113 114 if( size > (dwBlockSize - sizeof(BOOL)) ) 115 { 116 FIXME( "Size exceeded. Request of 0x%08x\n", size ); 117 size = dwBlockSize - sizeof(BOOL); 118 } 119 120 /* Find blank area */ 121 uBlockUsed = 0; 122 while( uBlockUsed < dwMaxBlock && lpMemArea[ uBlockUsed ].used ) { uBlockUsed++; } 123 124 if( uBlockUsed < dwMaxBlock ) 125 { 126 /* Set the area used */ 127 lpMemArea[ uBlockUsed ].used = TRUE; 128 lpvArea = lpMemArea[ uBlockUsed ].data; 129 } 130 else 131 { 132 ERR( "No free block found\n" ); 133 return NULL; 134 } 135 136 if( flags & HEAP_ZERO_MEMORY ) 137 { 138 ZeroMemory( lpvArea, size ); 139 } 140 141 return lpvArea; 142 } 143 144 145 enum { numSupportedLobbies = 32, numSupportedSessions = 32 }; 146 typedef struct tagDPLAYX_LOBBYDATA 147 { 148 /* Points to lpConn + block of contiguous extra memory for dynamic parts 149 * of the struct directly following 150 */ 151 LPDPLCONNECTION lpConn; 152 153 /* Information for dplobby interfaces */ 154 DWORD dwAppID; 155 DWORD dwAppLaunchedFromID; 156 157 /* Should this lobby app send messages to creator at important life 158 * stages 159 */ 160 HANDLE hInformOnAppStart; 161 HANDLE hInformOnAppDeath; 162 HANDLE hInformOnSettingRead; 163 164 /* Sundries */ 165 BOOL bWaitForConnectionSettings; 166 DWORD dwLobbyMsgThreadId; 167 168 169 } DPLAYX_LOBBYDATA, *LPDPLAYX_LOBBYDATA; 170 171 static DPLAYX_LOBBYDATA* lobbyData = NULL; 172 /* static DPLAYX_LOBBYDATA lobbyData[ numSupportedLobbies ]; */ 173 174 static DPSESSIONDESC2* sessionData = NULL; 175 /* static DPSESSIONDESC2* sessionData[ numSupportedSessions ]; */ 176 177 178 static void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData ) 179 { 180 ZeroMemory( lpData, sizeof( *lpData ) ); 181 } 182 183 /* NOTE: This must be called with the semaphore acquired. 184 * TRUE/FALSE with a pointer to its data returned. Pointer data is 185 * is only valid if TRUE is returned. 186 */ 187 static BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppID, LPDPLAYX_LOBBYDATA* lplpDplData ) 188 { 189 UINT i; 190 191 *lplpDplData = NULL; 192 193 if( dwAppID == 0 ) 194 { 195 dwAppID = GetCurrentProcessId(); 196 TRACE( "Translated dwAppID == 0 into 0x%08x\n", dwAppID ); 197 } 198 199 for( i=0; i < numSupportedLobbies; i++ ) 200 { 201 if( lobbyData[ i ].dwAppID == dwAppID ) 202 { 203 /* This process is lobbied */ 204 TRACE( "Found 0x%08x @ %u\n", dwAppID, i ); 205 *lplpDplData = &lobbyData[ i ]; 206 return TRUE; 207 } 208 } 209 210 return FALSE; 211 } 212 213 /* Reserve a spot for the new application. TRUE means success and FALSE failure. */ 214 BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID ) 215 { 216 UINT i; 217 218 /* 0 is the marker for unused application data slots */ 219 if( dwAppID == 0 ) 220 { 221 return FALSE; 222 } 223 224 DPLAYX_AcquireSemaphore(); 225 226 /* Find an empty space in the list and insert the data */ 227 for( i=0; i < numSupportedLobbies; i++ ) 228 { 229 if( lobbyData[ i ].dwAppID == 0 ) 230 { 231 /* This process is now lobbied */ 232 TRACE( "Setting lobbyData[%u] for (0x%08x,0x%08x)\n", 233 i, dwAppID, GetCurrentProcessId() ); 234 235 lobbyData[ i ].dwAppID = dwAppID; 236 lobbyData[ i ].dwAppLaunchedFromID = GetCurrentProcessId(); 237 238 /* FIXME: Where is the best place for this? In interface or here? */ 239 lobbyData[ i ].hInformOnAppStart = 0; 240 lobbyData[ i ].hInformOnAppDeath = 0; 241 lobbyData[ i ].hInformOnSettingRead = 0; 242 243 DPLAYX_ReleaseSemaphore(); 244 return TRUE; 245 } 246 } 247 248 ERR( "No empty lobbies\n" ); 249 250 DPLAYX_ReleaseSemaphore(); 251 return FALSE; 252 } 253 254 BOOL DPLAYX_SetLobbyHandles( DWORD dwAppID, 255 HANDLE hStart, HANDLE hDeath, HANDLE hConnRead ) 256 { 257 LPDPLAYX_LOBBYDATA lpLData; 258 259 /* Need to explicitly give lobby application. Can't set for yourself */ 260 if( dwAppID == 0 ) 261 { 262 return FALSE; 263 } 264 265 DPLAYX_AcquireSemaphore(); 266 267 if( !DPLAYX_IsAppIdLobbied( dwAppID, &lpLData ) ) 268 { 269 DPLAYX_ReleaseSemaphore(); 270 return FALSE; 271 } 272 273 lpLData->hInformOnAppStart = hStart; 274 lpLData->hInformOnAppDeath = hDeath; 275 lpLData->hInformOnSettingRead = hConnRead; 276 277 DPLAYX_ReleaseSemaphore(); 278 279 return TRUE; 280 } 281 282 static BOOL DPLAYX_GetThisLobbyHandles( LPHANDLE lphStart, 283 LPHANDLE lphDeath, 284 LPHANDLE lphConnRead, 285 BOOL bClearSetHandles ) 286 { 287 LPDPLAYX_LOBBYDATA lpLData; 288 289 DPLAYX_AcquireSemaphore(); 290 291 if( !DPLAYX_IsAppIdLobbied( 0, &lpLData ) ) 292 { 293 DPLAYX_ReleaseSemaphore(); 294 return FALSE; 295 } 296 297 if( lphStart != NULL ) 298 { 299 if( lpLData->hInformOnAppStart == 0 ) 300 { 301 DPLAYX_ReleaseSemaphore(); 302 return FALSE; 303 } 304 305 *lphStart = lpLData->hInformOnAppStart; 306 307 if( bClearSetHandles ) 308 { 309 CloseHandle( lpLData->hInformOnAppStart ); 310 lpLData->hInformOnAppStart = 0; 311 } 312 } 313 314 if( lphDeath != NULL ) 315 { 316 if( lpLData->hInformOnAppDeath == 0 ) 317 { 318 DPLAYX_ReleaseSemaphore(); 319 return FALSE; 320 } 321 322 *lphDeath = lpLData->hInformOnAppDeath; 323 324 if( bClearSetHandles ) 325 { 326 CloseHandle( lpLData->hInformOnAppDeath ); 327 lpLData->hInformOnAppDeath = 0; 328 } 329 } 330 331 if( lphConnRead != NULL ) 332 { 333 if( lpLData->hInformOnSettingRead == 0 ) 334 { 335 DPLAYX_ReleaseSemaphore(); 336 return FALSE; 337 } 338 339 *lphConnRead = lpLData->hInformOnSettingRead; 340 341 if( bClearSetHandles ) 342 { 343 CloseHandle( lpLData->hInformOnSettingRead ); 344 lpLData->hInformOnSettingRead = 0; 345 } 346 } 347 348 DPLAYX_ReleaseSemaphore(); 349 350 return TRUE; 351 } 352 353 /*************************************************************************** 354 * Called to initialize the global data. This will only be used on the 355 * loading of the dll 356 ***************************************************************************/ 357 BOOL DPLAYX_ConstructData(void) 358 { 359 SECURITY_ATTRIBUTES s_attrib; 360 BOOL bInitializeSharedMemory = FALSE; 361 LPVOID lpDesiredMemoryMapStart = (LPVOID)0x50000000; 362 HANDLE hInformOnStart; 363 364 TRACE( "DPLAYX dll loaded - construct called\n" ); 365 366 /* Create a semaphore to block access to DPLAYX global data structs */ 367 368 s_attrib.bInheritHandle = TRUE; 369 s_attrib.lpSecurityDescriptor = NULL; 370 s_attrib.nLength = sizeof(s_attrib); 371 372 hDplayxSema = CreateSemaphoreA( &s_attrib, 0, 1, lpszDplayxSemaName ); 373 374 /* First instance creates the semaphore. Others just use it */ 375 if( GetLastError() == ERROR_SUCCESS ) 376 { 377 TRACE( "Semaphore %p created\n", hDplayxSema ); 378 379 /* The semaphore creator will also build the shared memory */ 380 bInitializeSharedMemory = TRUE; 381 } 382 else if ( GetLastError() == ERROR_ALREADY_EXISTS ) 383 { 384 TRACE( "Found semaphore handle %p\n", hDplayxSema ); 385 DPLAYX_AcquireSemaphore(); 386 } 387 else 388 { 389 ERR( ": semaphore error %d\n", GetLastError() ); 390 return FALSE; 391 } 392 393 SetLastError( ERROR_SUCCESS ); 394 395 hDplayxSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE, 396 &s_attrib, 397 PAGE_READWRITE | SEC_COMMIT, 398 0, 399 dwTotalSharedSize, 400 lpszDplayxFileMapping ); 401 402 if( GetLastError() == ERROR_SUCCESS ) 403 { 404 TRACE( "File mapped %p created\n", hDplayxSharedMem ); 405 } 406 else if ( GetLastError() == ERROR_ALREADY_EXISTS ) 407 { 408 TRACE( "Found FileMapping handle %p\n", hDplayxSharedMem ); 409 } 410 else 411 { 412 ERR( ": unable to create shared memory (%d)\n", GetLastError() ); 413 DPLAYX_ReleaseSemaphore(); 414 return FALSE; 415 } 416 417 lpSharedStaticData = MapViewOfFileEx( hDplayxSharedMem, 418 FILE_MAP_WRITE, 419 0, 0, 0, lpDesiredMemoryMapStart ); 420 421 if( lpSharedStaticData == NULL ) 422 { 423 ERR( ": unable to map static data into process memory space (%d)\n", 424 GetLastError() ); 425 DPLAYX_ReleaseSemaphore(); 426 return FALSE; 427 } 428 else 429 { 430 if( lpDesiredMemoryMapStart == lpSharedStaticData ) 431 { 432 TRACE( "File mapped to %p\n", lpSharedStaticData ); 433 } 434 else 435 { 436 /* Presently the shared data structures use pointers. If the 437 * files are not mapped into the same area, the pointers will no 438 * longer make any sense :( 439 * FIXME: In the future make the shared data structures have some 440 * sort of fixup to make them independent between data spaces. 441 * This will also require a rework of the session data stuff. 442 */ 443 ERR( "File mapped to %p (not %p). Expect failure\n", 444 lpSharedStaticData, lpDesiredMemoryMapStart ); 445 } 446 } 447 448 /* Dynamic area starts just after the static area */ 449 lpMemArea = (LPVOID)((BYTE*)lpSharedStaticData + dwStaticSharedSize); 450 451 /* FIXME: Crude hack */ 452 lobbyData = lpSharedStaticData; 453 sessionData = (DPSESSIONDESC2*)((BYTE*)lpSharedStaticData + (dwStaticSharedSize/2)); 454 455 /* Initialize shared data segments. */ 456 if( bInitializeSharedMemory ) 457 { 458 UINT i; 459 460 TRACE( "Initializing shared memory\n" ); 461 462 /* Set all lobbies to be "empty" */ 463 for( i=0; i < numSupportedLobbies; i++ ) 464 { 465 DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] ); 466 } 467 468 /* Set all sessions to be "empty" */ 469 for( i=0; i < numSupportedSessions; i++ ) 470 { 471 sessionData[i].dwSize = 0; 472 } 473 474 /* Zero out the dynamic area */ 475 ZeroMemory( lpMemArea, dwDynamicSharedSize ); 476 477 /* Just for fun sync the whole data area */ 478 FlushViewOfFile( lpSharedStaticData, dwTotalSharedSize ); 479 } 480 481 DPLAYX_ReleaseSemaphore(); 482 483 /* Everything was created correctly. Signal the lobby client that 484 * we started up correctly 485 */ 486 if( DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, FALSE ) && 487 hInformOnStart 488 ) 489 { 490 BOOL bSuccess; 491 bSuccess = SetEvent( hInformOnStart ); 492 TRACE( "Signalling lobby app start event %p %s\n", 493 hInformOnStart, bSuccess ? "succeed" : "failed" ); 494 495 /* Close out handle */ 496 DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, TRUE ); 497 } 498 499 return TRUE; 500 } 501 502 /*************************************************************************** 503 * Called to destroy all global data. This will only be used on the 504 * unloading of the dll 505 ***************************************************************************/ 506 BOOL DPLAYX_DestructData(void) 507 { 508 HANDLE hInformOnDeath; 509 510 TRACE( "DPLAYX dll unloaded - destruct called\n" ); 511 512 /* If required, inform that this app is dying */ 513 if( DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, FALSE ) && 514 hInformOnDeath 515 ) 516 { 517 BOOL bSuccess; 518 bSuccess = SetEvent( hInformOnDeath ); 519 TRACE( "Signalling lobby app death event %p %s\n", 520 hInformOnDeath, bSuccess ? "succeed" : "failed" ); 521 522 /* Close out handle */ 523 DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, TRUE ); 524 } 525 526 /* DO CLEAN UP (LAST) */ 527 528 /* Delete the semaphore */ 529 CloseHandle( hDplayxSema ); 530 531 /* Delete shared memory file mapping */ 532 UnmapViewOfFile( lpSharedStaticData ); 533 CloseHandle( hDplayxSharedMem ); 534 535 return FALSE; 536 } 537 538 539 /* Assumption: Enough contiguous space was allocated at dest */ 540 static void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, const DPLCONNECTION *src ) 541 { 542 BYTE* lpStartOfFreeSpace; 543 544 *dest = *src; 545 546 lpStartOfFreeSpace = ((BYTE*)dest) + sizeof( DPLCONNECTION ); 547 548 /* Copy the LPDPSESSIONDESC2 structure if it exists */ 549 if( src->lpSessionDesc ) 550 { 551 dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace; 552 lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 ); 553 *dest->lpSessionDesc = *src->lpSessionDesc; 554 555 /* Session names may or may not exist */ 556 if( src->lpSessionDesc->u1.lpszSessionNameA ) 557 { 558 strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->u1.lpszSessionNameA ); 559 dest->lpSessionDesc->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace; 560 lpStartOfFreeSpace += 561 strlen( dest->lpSessionDesc->u1.lpszSessionNameA ) + 1; 562 } 563 564 if( src->lpSessionDesc->u2.lpszPasswordA ) 565 { 566 strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->u2.lpszPasswordA ); 567 dest->lpSessionDesc->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace; 568 lpStartOfFreeSpace += 569 strlen( dest->lpSessionDesc->u2.lpszPasswordA ) + 1; 570 } 571 } 572 573 /* DPNAME structure is optional */ 574 if( src->lpPlayerName ) 575 { 576 dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace; 577 lpStartOfFreeSpace += sizeof( DPNAME ); 578 *dest->lpPlayerName = *src->lpPlayerName; 579 580 if( src->lpPlayerName->u1.lpszShortNameA ) 581 { 582 strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->u1.lpszShortNameA ); 583 dest->lpPlayerName->u1.lpszShortNameA = (LPSTR)lpStartOfFreeSpace; 584 lpStartOfFreeSpace += 585 strlen( dest->lpPlayerName->u1.lpszShortNameA ) + 1; 586 } 587 588 if( src->lpPlayerName->u2.lpszLongNameA ) 589 { 590 strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->u2.lpszLongNameA ); 591 dest->lpPlayerName->u2.lpszLongNameA = (LPSTR)lpStartOfFreeSpace; 592 lpStartOfFreeSpace += 593 strlen( (LPSTR)dest->lpPlayerName->u2.lpszLongName ) + 1 ; 594 } 595 596 } 597 598 /* Copy address if it exists */ 599 if( src->lpAddress ) 600 { 601 dest->lpAddress = lpStartOfFreeSpace; 602 CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize ); 603 /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */ 604 } 605 } 606 607 /* Assumption: Enough contiguous space was allocated at dest */ 608 static void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, const DPLCONNECTION *src ) 609 { 610 BYTE* lpStartOfFreeSpace; 611 612 *dest = *src; 613 614 lpStartOfFreeSpace = ( (BYTE*)dest) + sizeof( DPLCONNECTION ); 615 616 /* Copy the LPDPSESSIONDESC2 structure if it exists */ 617 if( src->lpSessionDesc ) 618 { 619 dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace; 620 lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 ); 621 *dest->lpSessionDesc = *src->lpSessionDesc; 622 623 /* Session names may or may not exist */ 624 if( src->lpSessionDesc->u1.lpszSessionName ) 625 { 626 lstrcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpSessionDesc->u1.lpszSessionName ); 627 dest->lpSessionDesc->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace; 628 lpStartOfFreeSpace += sizeof(WCHAR) * 629 ( lstrlenW( dest->lpSessionDesc->u1.lpszSessionName ) + 1 ); 630 } 631 632 if( src->lpSessionDesc->u2.lpszPassword ) 633 { 634 lstrcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpSessionDesc->u2.lpszPassword ); 635 dest->lpSessionDesc->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace; 636 lpStartOfFreeSpace += sizeof(WCHAR) * 637 ( lstrlenW( dest->lpSessionDesc->u2.lpszPassword ) + 1 ); 638 } 639 } 640 641 /* DPNAME structure is optional */ 642 if( src->lpPlayerName ) 643 { 644 dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace; 645 lpStartOfFreeSpace += sizeof( DPNAME ); 646 *dest->lpPlayerName = *src->lpPlayerName; 647 648 if( src->lpPlayerName->u1.lpszShortName ) 649 { 650 lstrcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->u1.lpszShortName ); 651 dest->lpPlayerName->u1.lpszShortName = (LPWSTR)lpStartOfFreeSpace; 652 lpStartOfFreeSpace += sizeof(WCHAR) * 653 ( lstrlenW( dest->lpPlayerName->u1.lpszShortName ) + 1 ); 654 } 655 656 if( src->lpPlayerName->u2.lpszLongName ) 657 { 658 lstrcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->u2.lpszLongName ); 659 dest->lpPlayerName->u2.lpszLongName = (LPWSTR)lpStartOfFreeSpace; 660 lpStartOfFreeSpace += sizeof(WCHAR) * 661 ( lstrlenW( dest->lpPlayerName->u2.lpszLongName ) + 1 ); 662 } 663 664 } 665 666 /* Copy address if it exists */ 667 if( src->lpAddress ) 668 { 669 dest->lpAddress = lpStartOfFreeSpace; 670 CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize ); 671 /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */ 672 } 673 674 } 675 676 static DWORD DPLAYX_SizeOfLobbyDataA( const DPLCONNECTION *lpConn ) 677 { 678 DWORD dwTotalSize = sizeof( DPLCONNECTION ); 679 680 /* Just a safety check */ 681 if( lpConn == NULL ) 682 { 683 ERR( "lpConn is NULL\n" ); 684 return 0; 685 } 686 687 if( lpConn->lpSessionDesc != NULL ) 688 { 689 dwTotalSize += sizeof( DPSESSIONDESC2 ); 690 691 if( lpConn->lpSessionDesc->u1.lpszSessionNameA ) 692 { 693 dwTotalSize += strlen( lpConn->lpSessionDesc->u1.lpszSessionNameA ) + 1; 694 } 695 696 if( lpConn->lpSessionDesc->u2.lpszPasswordA ) 697 { 698 dwTotalSize += strlen( lpConn->lpSessionDesc->u2.lpszPasswordA ) + 1; 699 } 700 } 701 702 if( lpConn->lpPlayerName != NULL ) 703 { 704 dwTotalSize += sizeof( DPNAME ); 705 706 if( lpConn->lpPlayerName->u1.lpszShortNameA ) 707 { 708 dwTotalSize += strlen( lpConn->lpPlayerName->u1.lpszShortNameA ) + 1; 709 } 710 711 if( lpConn->lpPlayerName->u2.lpszLongNameA ) 712 { 713 dwTotalSize += strlen( lpConn->lpPlayerName->u2.lpszLongNameA ) + 1; 714 } 715 716 } 717 718 dwTotalSize += lpConn->dwAddressSize; 719 720 return dwTotalSize; 721 } 722 723 static DWORD DPLAYX_SizeOfLobbyDataW( const DPLCONNECTION *lpConn ) 724 { 725 DWORD dwTotalSize = sizeof( DPLCONNECTION ); 726 727 /* Just a safety check */ 728 if( lpConn == NULL ) 729 { 730 ERR( "lpConn is NULL\n" ); 731 return 0; 732 } 733 734 if( lpConn->lpSessionDesc != NULL ) 735 { 736 dwTotalSize += sizeof( DPSESSIONDESC2 ); 737 738 if( lpConn->lpSessionDesc->u1.lpszSessionName ) 739 { 740 dwTotalSize += sizeof( WCHAR ) * 741 ( lstrlenW( lpConn->lpSessionDesc->u1.lpszSessionName ) + 1 ); 742 } 743 744 if( lpConn->lpSessionDesc->u2.lpszPassword ) 745 { 746 dwTotalSize += sizeof( WCHAR ) * 747 ( lstrlenW( lpConn->lpSessionDesc->u2.lpszPassword ) + 1 ); 748 } 749 } 750 751 if( lpConn->lpPlayerName != NULL ) 752 { 753 dwTotalSize += sizeof( DPNAME ); 754 755 if( lpConn->lpPlayerName->u1.lpszShortName ) 756 { 757 dwTotalSize += sizeof( WCHAR ) * 758 ( lstrlenW( lpConn->lpPlayerName->u1.lpszShortName ) + 1 ); 759 } 760 761 if( lpConn->lpPlayerName->u2.lpszLongName ) 762 { 763 dwTotalSize += sizeof( WCHAR ) * 764 ( lstrlenW( lpConn->lpPlayerName->u2.lpszLongName ) + 1 ); 765 } 766 767 } 768 769 dwTotalSize += lpConn->dwAddressSize; 770 771 return dwTotalSize; 772 } 773 774 HRESULT DPLAYX_GetConnectionSettingsA 775 ( DWORD dwAppID, 776 LPVOID lpData, 777 LPDWORD lpdwDataSize ) 778 { 779 LPDPLAYX_LOBBYDATA lpDplData; 780 DWORD dwRequiredDataSize = 0; 781 HANDLE hInformOnSettingRead; 782 783 DPLAYX_AcquireSemaphore(); 784 785 if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) ) 786 { 787 DPLAYX_ReleaseSemaphore(); 788 789 TRACE( "Application 0x%08x is not lobbied\n", dwAppID ); 790 return DPERR_NOTLOBBIED; 791 } 792 793 dwRequiredDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn ); 794 795 /* Do they want to know the required buffer size or is the provided buffer 796 * big enough? 797 */ 798 if ( ( lpData == NULL ) || 799 ( *lpdwDataSize < dwRequiredDataSize ) 800 ) 801 { 802 DPLAYX_ReleaseSemaphore(); 803 804 *lpdwDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn ); 805 806 return DPERR_BUFFERTOOSMALL; 807 } 808 809 DPLAYX_CopyConnStructA( lpData, lpDplData->lpConn ); 810 811 DPLAYX_ReleaseSemaphore(); 812 813 /* They have gotten the information - signal the event if required */ 814 if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) && 815 hInformOnSettingRead 816 ) 817 { 818 BOOL bSuccess; 819 bSuccess = SetEvent( hInformOnSettingRead ); 820 TRACE( "Signalling setting read event %p %s\n", 821 hInformOnSettingRead, bSuccess ? "succeed" : "failed" ); 822 823 /* Close out handle */ 824 DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE ); 825 } 826 827 return DP_OK; 828 } 829 830 HRESULT DPLAYX_GetConnectionSettingsW 831 ( DWORD dwAppID, 832 LPVOID lpData, 833 LPDWORD lpdwDataSize ) 834 { 835 LPDPLAYX_LOBBYDATA lpDplData; 836 DWORD dwRequiredDataSize = 0; 837 HANDLE hInformOnSettingRead; 838 839 DPLAYX_AcquireSemaphore(); 840 841 if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) ) 842 { 843 DPLAYX_ReleaseSemaphore(); 844 return DPERR_NOTLOBBIED; 845 } 846 847 dwRequiredDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn ); 848 849 /* Do they want to know the required buffer size or is the provided buffer 850 * big enough? 851 */ 852 if ( ( lpData == NULL ) || 853 ( *lpdwDataSize < dwRequiredDataSize ) 854 ) 855 { 856 DPLAYX_ReleaseSemaphore(); 857 858 *lpdwDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn ); 859 860 return DPERR_BUFFERTOOSMALL; 861 } 862 863 DPLAYX_CopyConnStructW( lpData, lpDplData->lpConn ); 864 865 DPLAYX_ReleaseSemaphore(); 866 867 /* They have gotten the information - signal the event if required */ 868 if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) && 869 hInformOnSettingRead 870 ) 871 { 872 BOOL bSuccess; 873 bSuccess = SetEvent( hInformOnSettingRead ); 874 TRACE( "Signalling setting read event %p %s\n", 875 hInformOnSettingRead, bSuccess ? "succeed" : "failed" ); 876 877 /* Close out handle */ 878 DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE ); 879 } 880 881 return DP_OK; 882 } 883 884 /* Store the structure into the shared data structure. Ensure that allocs for 885 * variable length strings come from the shared data structure. 886 * FIXME: We need to free information as well. 887 */ 888 HRESULT DPLAYX_SetConnectionSettingsA 889 ( DWORD dwFlags, 890 DWORD dwAppID, 891 const DPLCONNECTION *lpConn ) 892 { 893 LPDPLAYX_LOBBYDATA lpDplData; 894 895 /* Parameter check */ 896 if( dwFlags || !lpConn ) 897 { 898 ERR("invalid parameters.\n"); 899 return DPERR_INVALIDPARAMS; 900 } 901 902 /* Store information */ 903 if( lpConn->dwSize != sizeof(DPLCONNECTION) ) 904 { 905 ERR(": old/new DPLCONNECTION type? Size=%08x\n", lpConn->dwSize ); 906 907 return DPERR_INVALIDPARAMS; 908 } 909 910 DPLAYX_AcquireSemaphore(); 911 912 if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) ) 913 { 914 DPLAYX_ReleaseSemaphore(); 915 916 return DPERR_NOTLOBBIED; 917 } 918 919 if( (!lpConn->lpSessionDesc ) || 920 ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) ) 921 ) 922 { 923 DPLAYX_ReleaseSemaphore(); 924 925 ERR("DPSESSIONDESC passed in? Size=%u\n", 926 lpConn->lpSessionDesc?lpConn->lpSessionDesc->dwSize:0 ); 927 928 return DPERR_INVALIDPARAMS; 929 } 930 931 /* Free the existing memory */ 932 DPLAYX_PrivHeapFree( lpDplData->lpConn ); 933 934 lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, 935 DPLAYX_SizeOfLobbyDataA( lpConn ) ); 936 937 DPLAYX_CopyConnStructA( lpDplData->lpConn, lpConn ); 938 939 940 DPLAYX_ReleaseSemaphore(); 941 942 /* FIXME: Send a message - I think */ 943 944 return DP_OK; 945 } 946 947 /* Store the structure into the shared data structure. Ensure that allocs for 948 * variable length strings come from the shared data structure. 949 * FIXME: We need to free information as well 950 */ 951 HRESULT DPLAYX_SetConnectionSettingsW 952 ( DWORD dwFlags, 953 DWORD dwAppID, 954 const DPLCONNECTION *lpConn ) 955 { 956 LPDPLAYX_LOBBYDATA lpDplData; 957 958 /* Parameter check */ 959 if( dwFlags || !lpConn ) 960 { 961 ERR("invalid parameters.\n"); 962 return DPERR_INVALIDPARAMS; 963 } 964 965 /* Store information */ 966 if( lpConn->dwSize != sizeof(DPLCONNECTION) ) 967 { 968 ERR(": old/new DPLCONNECTION type? Size=%u\n", lpConn->dwSize ); 969 970 return DPERR_INVALIDPARAMS; 971 } 972 973 DPLAYX_AcquireSemaphore(); 974 975 if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) ) 976 { 977 DPLAYX_ReleaseSemaphore(); 978 979 return DPERR_NOTLOBBIED; 980 } 981 982 /* Free the existing memory */ 983 DPLAYX_PrivHeapFree( lpDplData->lpConn ); 984 985 lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, 986 DPLAYX_SizeOfLobbyDataW( lpConn ) ); 987 988 DPLAYX_CopyConnStructW( lpDplData->lpConn, lpConn ); 989 990 991 DPLAYX_ReleaseSemaphore(); 992 993 /* FIXME: Send a message - I think */ 994 995 return DP_OK; 996 } 997 998 BOOL DPLAYX_WaitForConnectionSettings( BOOL bWait ) 999 { 1000 LPDPLAYX_LOBBYDATA lpLobbyData; 1001 1002 DPLAYX_AcquireSemaphore(); 1003 1004 if( !DPLAYX_IsAppIdLobbied( 0, &lpLobbyData ) ) 1005 { 1006 DPLAYX_ReleaseSemaphore(); 1007 return FALSE; 1008 } 1009 1010 lpLobbyData->bWaitForConnectionSettings = bWait; 1011 1012 DPLAYX_ReleaseSemaphore(); 1013 1014 return TRUE; 1015 } 1016 1017 BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void) 1018 { 1019 UINT i; 1020 BOOL bFound = FALSE; 1021 1022 DPLAYX_AcquireSemaphore(); 1023 1024 for( i=0; i < numSupportedLobbies; i++ ) 1025 { 1026 if( ( lobbyData[ i ].dwAppID != 0 ) && /* lobby initialized */ 1027 ( lobbyData[ i ].bWaitForConnectionSettings ) /* Waiting */ 1028 ) 1029 { 1030 bFound = TRUE; 1031 break; 1032 } 1033 } 1034 1035 DPLAYX_ReleaseSemaphore(); 1036 1037 return bFound; 1038 } 1039 1040 BOOL DPLAYX_SetLobbyMsgThreadId( DWORD dwAppId, DWORD dwThreadId ) 1041 { 1042 LPDPLAYX_LOBBYDATA lpLobbyData; 1043 1044 DPLAYX_AcquireSemaphore(); 1045 1046 if( !DPLAYX_IsAppIdLobbied( dwAppId, &lpLobbyData ) ) 1047 { 1048 DPLAYX_ReleaseSemaphore(); 1049 return FALSE; 1050 } 1051 1052 lpLobbyData->dwLobbyMsgThreadId = dwThreadId; 1053 1054 DPLAYX_ReleaseSemaphore(); 1055 1056 return TRUE; 1057 } 1058 1059 /* NOTE: This is potentially not thread safe. You are not guaranteed to end up 1060 with the correct string printed in the case where the HRESULT is not 1061 known. You will just get the last hr passed in. This can change 1062 over time if this method is used a lot :) */ 1063 LPCSTR DPLAYX_HresultToString(HRESULT hr) 1064 { 1065 static char szTempStr[12]; 1066 1067 switch (hr) 1068 { 1069 case DP_OK: 1070 return "DP_OK"; 1071 case DPERR_ALREADYINITIALIZED: 1072 return "DPERR_ALREADYINITIALIZED"; 1073 case DPERR_ACCESSDENIED: 1074 return "DPERR_ACCESSDENIED"; 1075 case DPERR_ACTIVEPLAYERS: 1076 return "DPERR_ACTIVEPLAYERS"; 1077 case DPERR_BUFFERTOOSMALL: 1078 return "DPERR_BUFFERTOOSMALL"; 1079 case DPERR_CANTADDPLAYER: 1080 return "DPERR_CANTADDPLAYER"; 1081 case DPERR_CANTCREATEGROUP: 1082 return "DPERR_CANTCREATEGROUP"; 1083 case DPERR_CANTCREATEPLAYER: 1084 return "DPERR_CANTCREATEPLAYER"; 1085 case DPERR_CANTCREATESESSION: 1086 return "DPERR_CANTCREATESESSION"; 1087 case DPERR_CAPSNOTAVAILABLEYET: 1088 return "DPERR_CAPSNOTAVAILABLEYET"; 1089 case DPERR_EXCEPTION: 1090 return "DPERR_EXCEPTION"; 1091 case DPERR_GENERIC: 1092 return "DPERR_GENERIC"; 1093 case DPERR_INVALIDFLAGS: 1094 return "DPERR_INVALIDFLAGS"; 1095 case DPERR_INVALIDOBJECT: 1096 return "DPERR_INVALIDOBJECT"; 1097 case DPERR_INVALIDPARAMS: 1098 return "DPERR_INVALIDPARAMS"; 1099 case DPERR_INVALIDPLAYER: 1100 return "DPERR_INVALIDPLAYER"; 1101 case DPERR_INVALIDGROUP: 1102 return "DPERR_INVALIDGROUP"; 1103 case DPERR_NOCAPS: 1104 return "DPERR_NOCAPS"; 1105 case DPERR_NOCONNECTION: 1106 return "DPERR_NOCONNECTION"; 1107 case DPERR_OUTOFMEMORY: 1108 return "DPERR_OUTOFMEMORY"; 1109 case DPERR_NOMESSAGES: 1110 return "DPERR_NOMESSAGES"; 1111 case DPERR_NONAMESERVERFOUND: 1112 return "DPERR_NONAMESERVERFOUND"; 1113 case DPERR_NOPLAYERS: 1114 return "DPERR_NOPLAYERS"; 1115 case DPERR_NOSESSIONS: 1116 return "DPERR_NOSESSIONS"; 1117 case DPERR_PENDING: 1118 return "DPERR_PENDING"; 1119 case DPERR_SENDTOOBIG: 1120 return "DPERR_SENDTOOBIG"; 1121 case DPERR_TIMEOUT: 1122 return "DPERR_TIMEOUT"; 1123 case DPERR_UNAVAILABLE: 1124 return "DPERR_UNAVAILABLE"; 1125 case DPERR_UNSUPPORTED: 1126 return "DPERR_UNSUPPORTED"; 1127 case DPERR_BUSY: 1128 return "DPERR_BUSY"; 1129 case DPERR_USERCANCEL: 1130 return "DPERR_USERCANCEL"; 1131 case DPERR_NOINTERFACE: 1132 return "DPERR_NOINTERFACE"; 1133 case DPERR_CANNOTCREATESERVER: 1134 return "DPERR_CANNOTCREATESERVER"; 1135 case DPERR_PLAYERLOST: 1136 return "DPERR_PLAYERLOST"; 1137 case DPERR_SESSIONLOST: 1138 return "DPERR_SESSIONLOST"; 1139 case DPERR_UNINITIALIZED: 1140 return "DPERR_UNINITIALIZED"; 1141 case DPERR_NONEWPLAYERS: 1142 return "DPERR_NONEWPLAYERS"; 1143 case DPERR_INVALIDPASSWORD: 1144 return "DPERR_INVALIDPASSWORD"; 1145 case DPERR_CONNECTING: 1146 return "DPERR_CONNECTING"; 1147 case DPERR_CONNECTIONLOST: 1148 return "DPERR_CONNECTIONLOST"; 1149 case DPERR_UNKNOWNMESSAGE: 1150 return "DPERR_UNKNOWNMESSAGE"; 1151 case DPERR_CANCELFAILED: 1152 return "DPERR_CANCELFAILED"; 1153 case DPERR_INVALIDPRIORITY: 1154 return "DPERR_INVALIDPRIORITY"; 1155 case DPERR_NOTHANDLED: 1156 return "DPERR_NOTHANDLED"; 1157 case DPERR_CANCELLED: 1158 return "DPERR_CANCELLED"; 1159 case DPERR_ABORTED: 1160 return "DPERR_ABORTED"; 1161 case DPERR_BUFFERTOOLARGE: 1162 return "DPERR_BUFFERTOOLARGE"; 1163 case DPERR_CANTCREATEPROCESS: 1164 return "DPERR_CANTCREATEPROCESS"; 1165 case DPERR_APPNOTSTARTED: 1166 return "DPERR_APPNOTSTARTED"; 1167 case DPERR_INVALIDINTERFACE: 1168 return "DPERR_INVALIDINTERFACE"; 1169 case DPERR_NOSERVICEPROVIDER: 1170 return "DPERR_NOSERVICEPROVIDER"; 1171 case DPERR_UNKNOWNAPPLICATION: 1172 return "DPERR_UNKNOWNAPPLICATION"; 1173 case DPERR_NOTLOBBIED: 1174 return "DPERR_NOTLOBBIED"; 1175 case DPERR_SERVICEPROVIDERLOADED: 1176 return "DPERR_SERVICEPROVIDERLOADED"; 1177 case DPERR_ALREADYREGISTERED: 1178 return "DPERR_ALREADYREGISTERED"; 1179 case DPERR_NOTREGISTERED: 1180 return "DPERR_NOTREGISTERED"; 1181 case DPERR_AUTHENTICATIONFAILED: 1182 return "DPERR_AUTHENTICATIONFAILED"; 1183 case DPERR_CANTLOADSSPI: 1184 return "DPERR_CANTLOADSSPI"; 1185 case DPERR_ENCRYPTIONFAILED: 1186 return "DPERR_ENCRYPTIONFAILED"; 1187 case DPERR_SIGNFAILED: 1188 return "DPERR_SIGNFAILED"; 1189 case DPERR_CANTLOADSECURITYPACKAGE: 1190 return "DPERR_CANTLOADSECURITYPACKAGE"; 1191 case DPERR_ENCRYPTIONNOTSUPPORTED: 1192 return "DPERR_ENCRYPTIONNOTSUPPORTED"; 1193 case DPERR_CANTLOADCAPI: 1194 return "DPERR_CANTLOADCAPI"; 1195 case DPERR_NOTLOGGEDIN: 1196 return "DPERR_NOTLOGGEDIN"; 1197 case DPERR_LOGONDENIED: 1198 return "DPERR_LOGONDENIED"; 1199 default: 1200 /* For errors not in the list, return HRESULT as a string 1201 This part is not thread safe */ 1202 WARN( "Unknown error 0x%08x\n", hr ); 1203 wsprintfA( szTempStr, "0x%08x", hr ); 1204 return szTempStr; 1205 } 1206 } 1207