dplayx_global.c 31.9 KB
Newer Older
1 2
/* dplayx.dll global data implementation.
 *
3
 * Copyright 1999,2000 - Peter Hunnisett
4 5
 *
 *
6 7 8 9 10 11 12 13 14 15 16 17
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21 22
 *
 *
 * NOTES: 
 *  o Implementation of all things which are associated with dplay on
Austin English's avatar
Austin English committed
23 24 25
 *    the computer - i.e. shared resources and such. Methods in this
 *    compilation unit should not call anything outside of this unit
 *    except base windows services and an interface to start the
26 27 28 29
 *    messaging thread.
 *  o Methods that begin with DPLAYX_ are used for dealing with
 *    dplayx.dll data which is accessible from all processes.
 *
30
 */
31

32
#include <stdarg.h>
33
#include <string.h>
34 35 36

#define NONAMELESSUNION
#define NONAMELESSSTRUCT
37
#include "wine/debug.h"
38
#include "windef.h"
39 40
#include "winbase.h"
#include "winerror.h"
41
#include "wine/unicode.h"
42 43 44

#include "wingdi.h"
#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 52 53

/* FIXME: Need to do all that fun other dll referencing type of stuff */

/* Static data for all processes */
54
static const char lpszDplayxSemaName[] = "WINE_DPLAYX_SM";
55 56
static HANDLE hDplayxSema;

57
static const char lpszDplayxFileMapping[] = "WINE_DPLAYX_FM";
58
static HANDLE hDplayxSharedMem;
59

60 61 62
static LPVOID lpSharedStaticData = NULL;


63
#define DPLAYX_AcquireSemaphore() TRACE( "Waiting for DPLAYX semaphore\n" ); \
64 65
                                  WaitForSingleObject( hDplayxSema, INFINITE );\
                                  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 73 74
#define dwStaticSharedSize (128 * 1024) /* 128 KBytes */
#define dwDynamicSharedSize (512 * 1024) /* 512 KBytes */
#define dwTotalSharedSize  ( dwStaticSharedSize + dwDynamicSharedSize )
75 76 77 78 79 80 81 82 83


/* FIXME: Is there no easier way? */

/* Pretend the entire dynamic area is carved up into 512 byte blocks.
 * Each block has 4 bytes which are 0 unless used */
#define dwBlockSize 512
#define dwMaxBlock  (dwDynamicSharedSize/dwBlockSize)

84
typedef struct
85 86 87 88 89
{
  DWORD used;
  DWORD data[dwBlockSize-sizeof(DWORD)];
} DPLAYX_MEM_SLICE;

90
static DPLAYX_MEM_SLICE* lpMemArea;
91

92
static void DPLAYX_PrivHeapFree( LPVOID addr )
93 94 95 96 97 98 99 100
{
  LPVOID lpAddrStart;
  DWORD dwBlockUsed;

  /* Handle getting passed a NULL */
  if( addr == NULL )
  {
    return;
101
  }
102

103
  lpAddrStart = (char*)addr - sizeof(DWORD); /* Find block header */
104
  dwBlockUsed =  ((BYTE*)lpAddrStart - (BYTE*)lpMemArea)/dwBlockSize;
105

106 107 108
  lpMemArea[ dwBlockUsed ].used = 0;
}

109
static LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size )
110 111 112 113 114 115
{
  LPVOID lpvArea = NULL;
  UINT   uBlockUsed;

  if( size > (dwBlockSize - sizeof(DWORD)) )
  {
116
    FIXME( "Size exceeded. Request of 0x%08x\n", size );
117
    size = dwBlockSize - sizeof(DWORD);
118
  }
119 120

  /* Find blank area */
121 122
  uBlockUsed = 0;
  while( ( lpMemArea[ uBlockUsed ].used != 0 ) && ( uBlockUsed <= dwMaxBlock ) ) { uBlockUsed++; }
123 124 125 126 127

  if( uBlockUsed <= dwMaxBlock )
  {
    /* Set the area used */
    lpMemArea[ uBlockUsed ].used = 1;
128
    lpvArea = lpMemArea[ uBlockUsed ].data;
129 130 131 132 133 134
  }
  else
  {
    ERR( "No free block found\n" );
    return NULL;
  }
135

136 137 138 139 140 141 142 143 144
  if( flags & HEAP_ZERO_MEMORY )
  {
    ZeroMemory( lpvArea, size );
  }

  return lpvArea;
}


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 158 159
  /* Should this lobby app send messages to creator at important life
   * stages
   */
160 161 162
  HANDLE hInformOnAppStart;
  HANDLE hInformOnAppDeath;
  HANDLE hInformOnSettingRead;
163

164
  /* Sundries */
165
  BOOL bWaitForConnectionSettings;
166
  DWORD dwLobbyMsgThreadId;
167

168 169

} DPLAYX_LOBBYDATA, *LPDPLAYX_LOBBYDATA;
170

171 172
static DPLAYX_LOBBYDATA* lobbyData = NULL;
/* static DPLAYX_LOBBYDATA lobbyData[ numSupportedLobbies ]; */
173

174
static DPSESSIONDESC2* sessionData = NULL;
175
/* static DPSESSIONDESC2* sessionData[ numSupportedSessions ]; */
176

177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
static void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData )
{
  ZeroMemory( lpData, sizeof( *lpData ) );
}

/* NOTE: This must be called with the semaphore acquired.
 * TRUE/FALSE with a pointer to it's data returned. Pointer data is
 * is only valid if TRUE is returned.
 */
static BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppID, LPDPLAYX_LOBBYDATA* lplpDplData )
{
  UINT i;

  *lplpDplData = NULL;

  if( dwAppID == 0 )
  {
    dwAppID = GetCurrentProcessId();
    TRACE( "Translated dwAppID == 0 into 0x%08x\n", dwAppID );
  }

  for( i=0; i < numSupportedLobbies; i++ )
  {
    if( lobbyData[ i ].dwAppID == dwAppID )
    {
      /* This process is lobbied */
      TRACE( "Found 0x%08x @ %u\n", dwAppID, i );
      *lplpDplData = &lobbyData[ i ];
      return TRUE;
    }
  }

  return FALSE;
}

/* Reserve a spot for the new application. TRUE means success and FALSE failure.  */
BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID )
{
  UINT i;

  /* 0 is the marker for unused application data slots */
  if( dwAppID == 0 )
  {
    return FALSE;
  }

  DPLAYX_AcquireSemaphore();

  /* Find an empty space in the list and insert the data */
  for( i=0; i < numSupportedLobbies; i++ )
  {
    if( lobbyData[ i ].dwAppID == 0 )
    {
      /* This process is now lobbied */
      TRACE( "Setting lobbyData[%u] for (0x%08x,0x%08x)\n",
              i, dwAppID, GetCurrentProcessId() );

      lobbyData[ i ].dwAppID              = dwAppID;
      lobbyData[ i ].dwAppLaunchedFromID  = GetCurrentProcessId();

      /* FIXME: Where is the best place for this? In interface or here? */
      lobbyData[ i ].hInformOnAppStart = 0;
      lobbyData[ i ].hInformOnAppDeath = 0;
      lobbyData[ i ].hInformOnSettingRead = 0;

      DPLAYX_ReleaseSemaphore();
      return TRUE;
    }
  }

  ERR( "No empty lobbies\n" );

  DPLAYX_ReleaseSemaphore();
  return FALSE;
}

BOOL DPLAYX_SetLobbyHandles( DWORD dwAppID,
                             HANDLE hStart, HANDLE hDeath, HANDLE hConnRead )
{
  LPDPLAYX_LOBBYDATA lpLData;

  /* Need to explicitly give lobby application. Can't set for yourself */
  if( dwAppID == 0 )
  {
    return FALSE;
  }

  DPLAYX_AcquireSemaphore();

  if( !DPLAYX_IsAppIdLobbied( dwAppID, &lpLData ) )
  {
    DPLAYX_ReleaseSemaphore();
    return FALSE;
  }

  lpLData->hInformOnAppStart    = hStart;
  lpLData->hInformOnAppDeath    = hDeath;
  lpLData->hInformOnSettingRead = hConnRead;

  DPLAYX_ReleaseSemaphore();

  return TRUE;
}

static BOOL DPLAYX_GetThisLobbyHandles( LPHANDLE lphStart,
                                        LPHANDLE lphDeath,
                                        LPHANDLE lphConnRead,
                                        BOOL     bClearSetHandles )
{
  LPDPLAYX_LOBBYDATA lpLData;

  DPLAYX_AcquireSemaphore();

  if( !DPLAYX_IsAppIdLobbied( 0, &lpLData ) )
  {
    DPLAYX_ReleaseSemaphore();
    return FALSE;
  }
296

297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
  if( lphStart != NULL )
  {
    if( lpLData->hInformOnAppStart == 0 )
    {
      DPLAYX_ReleaseSemaphore();
      return FALSE;
    }

    *lphStart = lpLData->hInformOnAppStart;

    if( bClearSetHandles )
    {
      CloseHandle( lpLData->hInformOnAppStart );
      lpLData->hInformOnAppStart = 0;
    }
  }

  if( lphDeath != NULL )
  {
    if( lpLData->hInformOnAppDeath == 0 )
    {
      DPLAYX_ReleaseSemaphore();
      return FALSE;
    }

    *lphDeath = lpLData->hInformOnAppDeath;

    if( bClearSetHandles )
    {
      CloseHandle( lpLData->hInformOnAppDeath );
      lpLData->hInformOnAppDeath = 0;
    }
  }

  if( lphConnRead != NULL )
  {
    if( lpLData->hInformOnSettingRead == 0 )
    {
      DPLAYX_ReleaseSemaphore();
      return FALSE;
    }

    *lphConnRead = lpLData->hInformOnSettingRead;

    if( bClearSetHandles )
    {
      CloseHandle( lpLData->hInformOnSettingRead );
      lpLData->hInformOnSettingRead = 0;
    }
  }

  DPLAYX_ReleaseSemaphore();

  return TRUE;
}
352

353 354 355 356
/***************************************************************************
 * Called to initialize the global data. This will only be used on the
 * loading of the dll
 ***************************************************************************/
357
BOOL DPLAYX_ConstructData(void)
358
{
359 360 361
  SECURITY_ATTRIBUTES s_attrib;
  BOOL                bInitializeSharedMemory = FALSE;
  LPVOID              lpDesiredMemoryMapStart = (LPVOID)0x50000000;
362
  HANDLE              hInformOnStart;
363 364 365

  TRACE( "DPLAYX dll loaded - construct called\n" );

366 367 368 369 370 371
  /* Create a semaphore to block access to DPLAYX global data structs */

  s_attrib.bInheritHandle       = TRUE;
  s_attrib.lpSecurityDescriptor = NULL;
  s_attrib.nLength              = sizeof(s_attrib);

372
  hDplayxSema = CreateSemaphoreA( &s_attrib, 0, 1, lpszDplayxSemaName );
373 374 375 376

  /* First instance creates the semaphore. Others just use it */
  if( GetLastError() == ERROR_SUCCESS )
  {
377
    TRACE( "Semaphore %p created\n", hDplayxSema );
378

379 380 381 382
    /* The semaphore creator will also build the shared memory */
    bInitializeSharedMemory = TRUE;
  }
  else if ( GetLastError() == ERROR_ALREADY_EXISTS )
383
  {
384
    TRACE( "Found semaphore handle %p\n", hDplayxSema );
385
    DPLAYX_AcquireSemaphore();
386 387 388
  }
  else
  {
389
    ERR( ": semaphore error %d\n", GetLastError() );
390
    return FALSE;
391 392
  }

393 394 395 396 397
  SetLastError( ERROR_SUCCESS );

  hDplayxSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE,
                                         &s_attrib,
                                         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 407
  }
  else if ( GetLastError() == ERROR_ALREADY_EXISTS )
  {
408
    TRACE( "Found FileMapping handle %p\n", hDplayxSharedMem );
409 410 411
  }
  else
  {
412
    ERR( ": unable to create shared memory (%d)\n", GetLastError() );
413
    DPLAYX_ReleaseSemaphore();
414
    return FALSE;
415 416
  }

417 418
  lpSharedStaticData = MapViewOfFileEx( hDplayxSharedMem,
                                        FILE_MAP_WRITE,
419 420 421
                                        0, 0, 0, lpDesiredMemoryMapStart );

  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 429 430 431 432 433 434 435 436
  else
  {
    if( lpDesiredMemoryMapStart == lpSharedStaticData )
    {
      TRACE( "File mapped to %p\n", lpSharedStaticData );
    }
    else
    {
      /* Presently the shared data structures use pointers. If the
437
       * files are not mapped into the same area, the pointers will no
438 439 440 441 442 443 444 445 446 447 448 449 450 451
       * longer make any sense :(
       * FIXME: In the future make the shared data structures have some
       *        sort of fixup to make them independent between data spaces.
       *        This will also require a rework of the session data stuff.
       */
      ERR( "File mapped to %p (not %p). Expect failure\n",
            lpSharedStaticData, lpDesiredMemoryMapStart );
    }
  }

  /* Dynamic area starts just after the static area */
  lpMemArea = (LPVOID)((BYTE*)lpSharedStaticData + dwStaticSharedSize);

  /* FIXME: Crude hack */
452
  lobbyData   = lpSharedStaticData;
453 454 455 456 457 458
  sessionData = (DPSESSIONDESC2*)((BYTE*)lpSharedStaticData + (dwStaticSharedSize/2));

  /* Initialize shared data segments. */
  if( bInitializeSharedMemory )
  {
    UINT i;
459

460 461
    TRACE( "Initializing shared memory\n" );

462
    /* Set all lobbies to be "empty" */
463 464 465 466 467 468 469 470 471 472 473
    for( i=0; i < numSupportedLobbies; i++ )
    {
      DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
    }

    /* Set all sessions to be "empty" */
    for( i=0; i < numSupportedSessions; i++ )
    {
      sessionData[i].dwSize = 0;
    }

Austin English's avatar
Austin English committed
474
    /* Zero out the dynamic area */
475 476 477 478 479
    ZeroMemory( lpMemArea, dwDynamicSharedSize );

    /* Just for fun sync the whole data area */
    FlushViewOfFile( lpSharedStaticData, dwTotalSharedSize );
  }
480

481 482
  DPLAYX_ReleaseSemaphore();

483 484 485 486
  /* Everything was created correctly. Signal the lobby client that
   * we started up correctly
   */
  if( DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, FALSE ) &&
487
      hInformOnStart
488 489 490 491
    )
  {
    BOOL bSuccess;
    bSuccess = SetEvent( hInformOnStart );
492
    TRACE( "Signalling lobby app start event %p %s\n",
493 494 495 496 497 498
             hInformOnStart, bSuccess ? "succeed" : "failed" );

    /* Close out handle */
    DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, TRUE );
  }

499
  return TRUE;
500 501
}

502 503 504 505
/***************************************************************************
 * Called to destroy all global data. This will only be used on the
 * unloading of the dll
 ***************************************************************************/
506
BOOL DPLAYX_DestructData(void)
507
{
508 509
  HANDLE hInformOnDeath;

510
  TRACE( "DPLAYX dll unloaded - destruct called\n" );
511

512 513
  /* If required, inform that this app is dying */
  if( DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, FALSE ) &&
514
      hInformOnDeath
515 516 517 518
    )
  {
    BOOL bSuccess;
    bSuccess = SetEvent( hInformOnDeath );
519
    TRACE( "Signalling lobby app death event %p %s\n",
520 521 522 523 524 525 526 527
             hInformOnDeath, bSuccess ? "succeed" : "failed" );

    /* Close out handle */
    DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, TRUE );
  }

  /* DO CLEAN UP (LAST) */

528
  /* Delete the semaphore */
529
  CloseHandle( hDplayxSema );
530

531 532 533 534 535
  /* Delete shared memory file mapping */
  UnmapViewOfFile( lpSharedStaticData );
  CloseHandle( hDplayxSharedMem );

  return FALSE;
536 537 538
}


539 540
/* Assumption: Enough contiguous space was allocated at dest */
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 549
  /* Copy the LPDPSESSIONDESC2 structure if it exists */
  if( src->lpSessionDesc )
550
  {
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
    dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
    lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
    *dest->lpSessionDesc = *src->lpSessionDesc;

    /* Session names may or may not exist */
    if( src->lpSessionDesc->u1.lpszSessionNameA )
    {
      strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->u1.lpszSessionNameA );
      dest->lpSessionDesc->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
      lpStartOfFreeSpace +=
        strlen( dest->lpSessionDesc->u1.lpszSessionNameA ) + 1;
    }

    if( src->lpSessionDesc->u2.lpszPasswordA )
    {
      strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->u2.lpszPasswordA );
      dest->lpSessionDesc->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
      lpStartOfFreeSpace +=
        strlen( dest->lpSessionDesc->u2.lpszPasswordA ) + 1;
    }
571 572
  }

573 574
  /* DPNAME structure is optional */
  if( src->lpPlayerName )
575
  {
576 577 578 579 580
    dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
    lpStartOfFreeSpace += sizeof( DPNAME );
    *dest->lpPlayerName = *src->lpPlayerName;

    if( src->lpPlayerName->u1.lpszShortNameA )
581
    {
582 583 584 585
      strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->u1.lpszShortNameA );
      dest->lpPlayerName->u1.lpszShortNameA = (LPSTR)lpStartOfFreeSpace;
      lpStartOfFreeSpace +=
        strlen( dest->lpPlayerName->u1.lpszShortNameA ) + 1;
586
    }
587 588 589 590 591 592 593 594 595

    if( src->lpPlayerName->u2.lpszLongNameA )
    {
      strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->u2.lpszLongNameA );
      dest->lpPlayerName->u2.lpszLongNameA = (LPSTR)lpStartOfFreeSpace;
      lpStartOfFreeSpace +=
        strlen( (LPSTR)dest->lpPlayerName->u2.lpszLongName ) + 1 ;
    }

596 597
  }

598 599 600 601 602 603 604
  /* Copy address if it exists */
  if( src->lpAddress )
  {
    dest->lpAddress = lpStartOfFreeSpace;
    CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );
    /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */
  }
605 606
}

607 608
/* Assumption: Enough contiguous space was allocated at dest */
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 617
  /* Copy the LPDPSESSIONDESC2 structure if it exists */
  if( src->lpSessionDesc )
618
  {
619 620 621
    dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
    lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
    *dest->lpSessionDesc = *src->lpSessionDesc;
622

623 624 625 626 627 628 629 630
    /* Session names may or may not exist */
    if( src->lpSessionDesc->u1.lpszSessionName )
    {
      strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpSessionDesc->u1.lpszSessionName );
      dest->lpSessionDesc->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
      lpStartOfFreeSpace +=  sizeof(WCHAR) *
        ( strlenW( dest->lpSessionDesc->u1.lpszSessionName ) + 1 );
    }
631

632 633 634 635 636 637
    if( src->lpSessionDesc->u2.lpszPassword )
    {
      strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpSessionDesc->u2.lpszPassword );
      dest->lpSessionDesc->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
      lpStartOfFreeSpace +=  sizeof(WCHAR) *
        ( strlenW( dest->lpSessionDesc->u2.lpszPassword ) + 1 );
638 639
    }
  }
640

641 642 643 644 645 646
  /* DPNAME structure is optional */
  if( src->lpPlayerName )
  {
    dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
    lpStartOfFreeSpace += sizeof( DPNAME );
    *dest->lpPlayerName = *src->lpPlayerName;
647

648 649 650 651 652 653 654
    if( src->lpPlayerName->u1.lpszShortName )
    {
      strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->u1.lpszShortName );
      dest->lpPlayerName->u1.lpszShortName = (LPWSTR)lpStartOfFreeSpace;
      lpStartOfFreeSpace +=  sizeof(WCHAR) *
        ( strlenW( dest->lpPlayerName->u1.lpszShortName ) + 1 );
    }
655

656 657 658 659 660 661 662
    if( src->lpPlayerName->u2.lpszLongName )
    {
      strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->u2.lpszLongName );
      dest->lpPlayerName->u2.lpszLongName = (LPWSTR)lpStartOfFreeSpace;
      lpStartOfFreeSpace +=  sizeof(WCHAR) *
        ( strlenW( dest->lpPlayerName->u2.lpszLongName ) + 1 );
    }
663 664 665

  }

666 667
  /* Copy address if it exists */
  if( src->lpAddress )
668
  {
669 670 671
    dest->lpAddress = lpStartOfFreeSpace;
    CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );
    /* 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 681
  /* Just a safety check */
  if( lpConn == NULL )
682
  {
683 684
    ERR( "lpConn is NULL\n" );
    return 0;
685 686
  }

687
  if( lpConn->lpSessionDesc != NULL )
688
  {
689 690 691
    dwTotalSize += sizeof( DPSESSIONDESC2 );

    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 705 706
    dwTotalSize += sizeof( DPNAME );

    if( lpConn->lpPlayerName->u1.lpszShortNameA )
707
    {
708
      dwTotalSize += strlen( lpConn->lpPlayerName->u1.lpszShortNameA ) + 1;
709 710
    }

711 712 713 714
    if( lpConn->lpPlayerName->u2.lpszLongNameA )
    {
      dwTotalSize += strlen( lpConn->lpPlayerName->u2.lpszLongNameA ) + 1;
    }
715

716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
  }

  dwTotalSize += lpConn->dwAddressSize;

  return dwTotalSize;
}

static DWORD DPLAYX_SizeOfLobbyDataW( const DPLCONNECTION *lpConn )
{
  DWORD dwTotalSize = sizeof( DPLCONNECTION );

  /* Just a safety check */
  if( lpConn == NULL )
  {
    ERR( "lpConn is NULL\n" );
    return 0;
  }

  if( lpConn->lpSessionDesc != NULL )
  {
    dwTotalSize += sizeof( DPSESSIONDESC2 );

    if( lpConn->lpSessionDesc->u1.lpszSessionName )
739
    {
740 741 742 743 744 745 746 747
      dwTotalSize += sizeof( WCHAR ) *
        ( strlenW( lpConn->lpSessionDesc->u1.lpszSessionName ) + 1 );
    }

    if( lpConn->lpSessionDesc->u2.lpszPassword )
    {
      dwTotalSize += sizeof( WCHAR ) *
        ( strlenW( lpConn->lpSessionDesc->u2.lpszPassword ) + 1 );
748 749 750
    }
  }

751
  if( lpConn->lpPlayerName != NULL )
752
  {
753 754 755
    dwTotalSize += sizeof( DPNAME );

    if( lpConn->lpPlayerName->u1.lpszShortName )
756
    {
757 758
      dwTotalSize += sizeof( WCHAR ) *
        ( strlenW( lpConn->lpPlayerName->u1.lpszShortName ) + 1 );
759 760
    }

761
    if( lpConn->lpPlayerName->u2.lpszLongName )
762
    {
763 764
      dwTotalSize += sizeof( WCHAR ) *
        ( strlenW( lpConn->lpPlayerName->u2.lpszLongName ) + 1 );
765
    }
766

767
  }
768

769
  dwTotalSize += lpConn->dwAddressSize;
770

771
  return dwTotalSize;
772 773
}

774 775 776
HRESULT DPLAYX_GetConnectionSettingsA
( DWORD dwAppID,
  LPVOID lpData,
777
  LPDWORD lpdwDataSize )
778
{
779 780
  LPDPLAYX_LOBBYDATA lpDplData;
  DWORD              dwRequiredDataSize = 0;
781
  HANDLE             hInformOnSettingRead;
782

783
  DPLAYX_AcquireSemaphore();
784 785 786 787

  if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
  {
    DPLAYX_ReleaseSemaphore();
Peter Hunnisett's avatar
Peter Hunnisett committed
788

789
    TRACE( "Application 0x%08x is not lobbied\n", dwAppID );
790 791 792
    return DPERR_NOTLOBBIED;
  }

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 799 800 801 802
   */
  if ( ( lpData == NULL ) ||
       ( *lpdwDataSize < dwRequiredDataSize )
     )
  {
    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 814
  /* They have gotten the information - signal the event if required */
  if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) &&
815
      hInformOnSettingRead
816 817 818 819
    )
  {
    BOOL bSuccess;
    bSuccess = SetEvent( hInformOnSettingRead );
820
    TRACE( "Signalling setting read event %p %s\n",
821 822 823 824 825 826
             hInformOnSettingRead, bSuccess ? "succeed" : "failed" );

    /* Close out handle */
    DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE );
  }

827 828 829
  return DP_OK;
}

830 831 832
HRESULT DPLAYX_GetConnectionSettingsW
( DWORD dwAppID,
  LPVOID lpData,
833
  LPDWORD lpdwDataSize )
834
{
835 836
  LPDPLAYX_LOBBYDATA lpDplData;
  DWORD              dwRequiredDataSize = 0;
837
  HANDLE             hInformOnSettingRead;
838

839
  DPLAYX_AcquireSemaphore();
840 841 842 843 844 845 846

  if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
  {
    DPLAYX_ReleaseSemaphore();
    return DPERR_NOTLOBBIED;
  }

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 853 854 855 856
   */
  if ( ( lpData == NULL ) ||
       ( *lpdwDataSize < dwRequiredDataSize )
     )
  {
    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 868
  /* They have gotten the information - signal the event if required */
  if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) &&
869
      hInformOnSettingRead
870 871 872 873
    )
  {
    BOOL bSuccess;
    bSuccess = SetEvent( hInformOnSettingRead );
874
    TRACE( "Signalling setting read event %p %s\n",
875 876 877 878 879 880
             hInformOnSettingRead, bSuccess ? "succeed" : "failed" );

    /* Close out handle */
    DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE );
  }

881 882 883
  return DP_OK;
}

Austin English's avatar
Austin English committed
884
/* Store the structure into the shared data structure. Ensure that allocs for
885
 * variable length strings come from the shared data structure.
Austin English's avatar
Austin English committed
886
 * FIXME: We need to free information as well.
887
 */
888 889 890
HRESULT DPLAYX_SetConnectionSettingsA
( DWORD dwFlags,
  DWORD dwAppID,
891
  const DPLCONNECTION *lpConn )
892
{
893
  LPDPLAYX_LOBBYDATA lpDplData;
894

Francois Gouget's avatar
Francois Gouget committed
895
  /* Parameter check */
896 897 898 899 900
  if( dwFlags || !lpConn )
  {
    ERR("invalid parameters.\n");
    return DPERR_INVALIDPARAMS;
  }
901

902 903
  /* Store information */
  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 915
  {
    DPLAYX_ReleaseSemaphore();

916
    return DPERR_NOTLOBBIED;
917 918 919 920 921 922 923 924
  }

  if(  (!lpConn->lpSessionDesc ) ||
       ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
    )
  {
    DPLAYX_ReleaseSemaphore();

925 926
    ERR("DPSESSIONDESC passed in? Size=%u\n",
        lpConn->lpSessionDesc?lpConn->lpSessionDesc->dwSize:0 );
927 928 929 930

    return DPERR_INVALIDPARAMS;
  }

931 932
  /* Free the existing memory */
  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 945 946

  return DP_OK;
}

Austin English's avatar
Austin English committed
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 952 953
HRESULT DPLAYX_SetConnectionSettingsW
( DWORD dwFlags,
  DWORD dwAppID,
954
  const DPLCONNECTION *lpConn )
955
{
956
  LPDPLAYX_LOBBYDATA lpDplData;
957

Francois Gouget's avatar
Francois Gouget committed
958
  /* Parameter check */
959 960 961 962 963 964 965 966 967
  if( dwFlags || !lpConn )
  {
    ERR("invalid parameters.\n");
    return DPERR_INVALIDPARAMS;
  }

  /* Store information */
  if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
  {
968
    ERR(": old/new DPLCONNECTION type? Size=%u\n", lpConn->dwSize );
969 970 971 972

    return DPERR_INVALIDPARAMS;
  }

973
  DPLAYX_AcquireSemaphore();
974 975 976 977

  if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
  {
    DPLAYX_ReleaseSemaphore();
978

979 980 981
    return DPERR_NOTLOBBIED;
  }

982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001
  /* Free the existing memory */
  DPLAYX_PrivHeapFree( lpDplData->lpConn );

  lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
                                            DPLAYX_SizeOfLobbyDataW( lpConn ) );

  DPLAYX_CopyConnStructW( lpDplData->lpConn, lpConn );


  DPLAYX_ReleaseSemaphore();

  /* FIXME: Send a message - I think */

  return DP_OK;
}

BOOL DPLAYX_WaitForConnectionSettings( BOOL bWait )
{
  LPDPLAYX_LOBBYDATA lpLobbyData;

1002
  DPLAYX_AcquireSemaphore();
1003

1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
  if( !DPLAYX_IsAppIdLobbied( 0, &lpLobbyData ) )
  {
    DPLAYX_ReleaseSemaphore();
    return FALSE;
  }

  lpLobbyData->bWaitForConnectionSettings = bWait;

  DPLAYX_ReleaseSemaphore();

  return TRUE;
}

BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void)
{
  UINT i;
  BOOL bFound = FALSE;

1022
  DPLAYX_AcquireSemaphore();
1023 1024 1025 1026 1027 1028

  for( i=0; i < numSupportedLobbies; i++ )
  {
    if( ( lobbyData[ i ].dwAppID != 0 ) &&            /* lobby initialized */
        ( lobbyData[ i ].bWaitForConnectionSettings ) /* Waiting */
      )
1029
    {
1030
      bFound = TRUE;
1031
      break;
1032 1033 1034 1035 1036 1037 1038 1039
    }
  }

  DPLAYX_ReleaseSemaphore();

  return bFound;
}

1040 1041 1042 1043
BOOL DPLAYX_SetLobbyMsgThreadId( DWORD dwAppId, DWORD dwThreadId )
{
  LPDPLAYX_LOBBYDATA lpLobbyData;

1044
  DPLAYX_AcquireSemaphore();
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057

  if( !DPLAYX_IsAppIdLobbied( dwAppId, &lpLobbyData ) )
  {
    DPLAYX_ReleaseSemaphore();
    return FALSE;
  }

  lpLobbyData->dwLobbyMsgThreadId = dwThreadId;

  DPLAYX_ReleaseSemaphore();

  return TRUE;
}
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 1062
         known. You will just get the last hr passed in. This can change
         over time if this method is used a lot :) */
1063 1064 1065 1066 1067 1068
LPCSTR DPLAYX_HresultToString(HRESULT hr)
{
  static char szTempStr[12];

  switch (hr)
  {
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 1149 1150
      return "DPERR_CONNECTIONLOST";
    case DPERR_UNKNOWNMESSAGE:
      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 1199 1200 1201
      return "DPERR_LOGONDENIED";
    default:
      /* For errors not in the list, return HRESULT as a string
         This part is not thread safe */
1202
      WARN( "Unknown error 0x%08x\n", hr );
1203
      wsprintfA( szTempStr, "0x%08lx", hr );
1204 1205 1206
      return szTempStr;
  }
}