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