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