~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/dplayx/dplayx_global.c

Version: ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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 #define NONAMELESSSTRUCT
 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   DWORD used;
 87   DWORD data[dwBlockSize-sizeof(DWORD)];
 88 } DPLAYX_MEM_SLICE;
 89 
 90 static DPLAYX_MEM_SLICE* lpMemArea;
 91 
 92 void DPLAYX_PrivHeapFree( LPVOID addr );
 93 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 = (char*)addr - sizeof(DWORD); /* Find block header */
105   dwBlockUsed =  ((BYTE*)lpAddrStart - (BYTE*)lpMemArea)/dwBlockSize;
106 
107   lpMemArea[ dwBlockUsed ].used = 0;
108 }
109 
110 /* FIXME: This should be static, but is being used for a hack right now */
111 LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size );
112 LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size )
113 {
114   LPVOID lpvArea = NULL;
115   UINT   uBlockUsed;
116 
117   if( size > (dwBlockSize - sizeof(DWORD)) )
118   {
119     FIXME( "Size exceeded. Request of 0x%08x\n", size );
120     size = dwBlockSize - sizeof(DWORD);
121   }
122 
123   /* Find blank area */
124   uBlockUsed = 0;
125   while( ( lpMemArea[ uBlockUsed ].used != 0 ) && ( uBlockUsed <= dwMaxBlock ) ) { uBlockUsed++; }
126 
127   if( uBlockUsed <= dwMaxBlock )
128   {
129     /* Set the area used */
130     lpMemArea[ uBlockUsed ].used = 1;
131     lpvArea = &(lpMemArea[ uBlockUsed ].data);
132   }
133   else
134   {
135     ERR( "No free block found\n" );
136     return NULL;
137   }
138 
139   if( flags & HEAP_ZERO_MEMORY )
140   {
141     ZeroMemory( lpvArea, size );
142   }
143 
144   return lpvArea;
145 }
146 
147 LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str );
148 LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str )
149 {
150   LPSTR p = DPLAYX_PrivHeapAlloc( flags, strlen(str) + 1 );
151   if(p) {
152     strcpy( p, str );
153   }
154   return p;
155 }
156 
157 LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str );
158 LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str )
159 {
160   INT len = strlenW(str) + 1;
161   LPWSTR p = DPLAYX_PrivHeapAlloc( flags, len * sizeof(WCHAR) );
162   if(p) {
163     strcpyW( p, str );
164   }
165   return p;
166 }
167 
168 
169 enum { numSupportedLobbies = 32, numSupportedSessions = 32 };
170 typedef struct tagDPLAYX_LOBBYDATA
171 {
172   /* Points to lpConn + block of contiguous extra memory for dynamic parts
173    * of the struct directly following
174    */
175   LPDPLCONNECTION lpConn;
176 
177   /* Information for dplobby interfaces */
178   DWORD           dwAppID;
179   DWORD           dwAppLaunchedFromID;
180 
181   /* Should this lobby app send messages to creator at important life
182    * stages
183    */
184   HANDLE hInformOnAppStart;
185   HANDLE hInformOnAppDeath;
186   HANDLE hInformOnSettingRead;
187 
188   /* Sundries */
189   BOOL bWaitForConnectionSettings;
190   DWORD dwLobbyMsgThreadId;
191 
192 
193 } DPLAYX_LOBBYDATA, *LPDPLAYX_LOBBYDATA;
194 
195 static DPLAYX_LOBBYDATA* lobbyData = NULL;
196 /* static DPLAYX_LOBBYDATA lobbyData[ numSupportedLobbies ]; */
197 
198 static DPSESSIONDESC2* sessionData = NULL;
199 /* static DPSESSIONDESC2* sessionData[ numSupportedSessions ]; */
200 
201 /* Function prototypes */
202 static DWORD DPLAYX_SizeOfLobbyDataA( const DPLCONNECTION *lpDplData );
203 static DWORD DPLAYX_SizeOfLobbyDataW( const DPLCONNECTION *lpDplData );
204 static void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, const DPLCONNECTION *src );
205 static void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, const DPLCONNECTION *src );
206 static BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppId, LPDPLAYX_LOBBYDATA* dplData );
207 static void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData );
208 static BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2  lpSessionDest,
209                                           LPCDPSESSIONDESC2 lpSessionSrc );
210 static BOOL DPLAYX_GetThisLobbyHandles( LPHANDLE lphStart, LPHANDLE lphDeath,
211                                         LPHANDLE lphConnRead, BOOL bClearSetHandles );
212 
213 
214 
215 /***************************************************************************
216  * Called to initialize the global data. This will only be used on the
217  * loading of the dll
218  ***************************************************************************/
219 BOOL DPLAYX_ConstructData(void)
220 {
221   SECURITY_ATTRIBUTES s_attrib;
222   BOOL                bInitializeSharedMemory = FALSE;
223   LPVOID              lpDesiredMemoryMapStart = (LPVOID)0x50000000;
224   HANDLE              hInformOnStart;
225 
226   TRACE( "DPLAYX dll loaded - construct called\n" );
227 
228   /* Create a semaphore to block access to DPLAYX global data structs */
229 
230   s_attrib.bInheritHandle       = TRUE;
231   s_attrib.lpSecurityDescriptor = NULL;
232   s_attrib.nLength              = sizeof(s_attrib);
233 
234   hDplayxSema = CreateSemaphoreA( &s_attrib, 0, 1, lpszDplayxSemaName );
235 
236   /* First instance creates the semaphore. Others just use it */
237   if( GetLastError() == ERROR_SUCCESS )
238   {
239     TRACE( "Semaphore %p created\n", hDplayxSema );
240 
241     /* The semaphore creator will also build the shared memory */
242     bInitializeSharedMemory = TRUE;
243   }
244   else if ( GetLastError() == ERROR_ALREADY_EXISTS )
245   {
246     TRACE( "Found semaphore handle %p\n", hDplayxSema );
247     DPLAYX_AcquireSemaphore();
248   }
249   else
250   {
251     ERR( ": semaphore error %d\n", GetLastError() );
252     return FALSE;
253   }
254 
255   SetLastError( ERROR_SUCCESS );
256 
257   hDplayxSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE,
258                                          &s_attrib,
259                                          PAGE_READWRITE | SEC_COMMIT,
260                                          0,
261                                          dwTotalSharedSize,
262                                          lpszDplayxFileMapping );
263 
264   if( GetLastError() == ERROR_SUCCESS )
265   {
266     TRACE( "File mapped %p created\n", hDplayxSharedMem );
267   }
268   else if ( GetLastError() == ERROR_ALREADY_EXISTS )
269   {
270     TRACE( "Found FileMapping handle %p\n", hDplayxSharedMem );
271   }
272   else
273   {
274     ERR( ": unable to create shared memory (%d)\n", GetLastError() );
275     DPLAYX_ReleaseSemaphore();
276     return FALSE;
277   }
278 
279   lpSharedStaticData = MapViewOfFileEx( hDplayxSharedMem,
280                                         FILE_MAP_WRITE,
281                                         0, 0, 0, lpDesiredMemoryMapStart );
282 
283   if( lpSharedStaticData == NULL )
284   {
285     ERR( ": unable to map static data into process memory space (%d)\n",
286          GetLastError() );
287     DPLAYX_ReleaseSemaphore();
288     return FALSE;
289   }
290   else
291   {
292     if( lpDesiredMemoryMapStart == lpSharedStaticData )
293     {
294       TRACE( "File mapped to %p\n", lpSharedStaticData );
295     }
296     else
297     {
298       /* Presently the shared data structures use pointers. If the
299        * files are no mapped into the same area, the pointers will no
300        * longer make any sense :(
301        * FIXME: In the future make the shared data structures have some
302        *        sort of fixup to make them independent between data spaces.
303        *        This will also require a rework of the session data stuff.
304        */
305       ERR( "File mapped to %p (not %p). Expect failure\n",
306             lpSharedStaticData, lpDesiredMemoryMapStart );
307     }
308   }
309 
310   /* Dynamic area starts just after the static area */
311   lpMemArea = (LPVOID)((BYTE*)lpSharedStaticData + dwStaticSharedSize);
312 
313   /* FIXME: Crude hack */
314   lobbyData   = (DPLAYX_LOBBYDATA*)lpSharedStaticData;
315   sessionData = (DPSESSIONDESC2*)((BYTE*)lpSharedStaticData + (dwStaticSharedSize/2));
316 
317   /* Initialize shared data segments. */
318   if( bInitializeSharedMemory )
319   {
320     UINT i;
321 
322     TRACE( "Initializing shared memory\n" );
323 
324     /* Set all lobbies to be "empty" */
325     for( i=0; i < numSupportedLobbies; i++ )
326     {
327       DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
328     }
329 
330     /* Set all sessions to be "empty" */
331     for( i=0; i < numSupportedSessions; i++ )
332     {
333       sessionData[i].dwSize = 0;
334     }
335 
336     /* Zero out the dynamic area */
337     ZeroMemory( lpMemArea, dwDynamicSharedSize );
338 
339     /* Just for fun sync the whole data area */
340     FlushViewOfFile( lpSharedStaticData, dwTotalSharedSize );
341   }
342 
343   DPLAYX_ReleaseSemaphore();
344 
345   /* Everything was created correctly. Signal the lobby client that
346    * we started up correctly
347    */
348   if( DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, FALSE ) &&
349       hInformOnStart
350     )
351   {
352     BOOL bSuccess;
353     bSuccess = SetEvent( hInformOnStart );
354     TRACE( "Signalling lobby app start event %p %s\n",
355              hInformOnStart, bSuccess ? "succeed" : "failed" );
356 
357     /* Close out handle */
358     DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, TRUE );
359   }
360 
361   return TRUE;
362 }
363 
364 /***************************************************************************
365  * Called to destroy all global data. This will only be used on the
366  * unloading of the dll
367  ***************************************************************************/
368 BOOL DPLAYX_DestructData(void)
369 {
370   HANDLE hInformOnDeath;
371 
372   TRACE( "DPLAYX dll unloaded - destruct called\n" );
373 
374   /* If required, inform that this app is dying */
375   if( DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, FALSE ) &&
376       hInformOnDeath
377     )
378   {
379     BOOL bSuccess;
380     bSuccess = SetEvent( hInformOnDeath );
381     TRACE( "Signalling lobby app death event %p %s\n",
382              hInformOnDeath, bSuccess ? "succeed" : "failed" );
383 
384     /* Close out handle */
385     DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, TRUE );
386   }
387 
388   /* DO CLEAN UP (LAST) */
389 
390   /* Delete the semaphore */
391   CloseHandle( hDplayxSema );
392 
393   /* Delete shared memory file mapping */
394   UnmapViewOfFile( lpSharedStaticData );
395   CloseHandle( hDplayxSharedMem );
396 
397   return FALSE;
398 }
399 
400 
401 void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData )
402 {
403   ZeroMemory( lpData, sizeof( *lpData ) );
404 }
405 
406 /* NOTE: This must be called with the semaphore acquired.
407  * TRUE/FALSE with a pointer to it's data returned. Pointer data is
408  * is only valid if TRUE is returned.
409  */
410 BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppID, LPDPLAYX_LOBBYDATA* lplpDplData )
411 {
412   UINT i;
413 
414   *lplpDplData = NULL;
415 
416   if( dwAppID == 0 )
417   {
418     dwAppID = GetCurrentProcessId();
419     TRACE( "Translated dwAppID == 0 into 0x%08x\n", dwAppID );
420   }
421 
422   for( i=0; i < numSupportedLobbies; i++ )
423   {
424     if( lobbyData[ i ].dwAppID == dwAppID )
425     {
426       /* This process is lobbied */
427       TRACE( "Found 0x%08x @ %u\n", dwAppID, i );
428       *lplpDplData = &lobbyData[ i ];
429       return TRUE;
430     }
431   }
432 
433   return FALSE;
434 }
435 
436 /* Reserve a spot for the new application. TRUE means success and FALSE failure.  */
437 BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID )
438 {
439   UINT i;
440 
441   /* 0 is the marker for unused application data slots */
442   if( dwAppID == 0 )
443   {
444     return FALSE;
445   }
446 
447   DPLAYX_AcquireSemaphore();
448 
449   /* Find an empty space in the list and insert the data */
450   for( i=0; i < numSupportedLobbies; i++ )
451   {
452     if( lobbyData[ i ].dwAppID == 0 )
453     {
454       /* This process is now lobbied */
455       TRACE( "Setting lobbyData[%u] for (0x%08x,0x%08x)\n",
456               i, dwAppID, GetCurrentProcessId() );
457 
458       lobbyData[ i ].dwAppID              = dwAppID;
459       lobbyData[ i ].dwAppLaunchedFromID  = GetCurrentProcessId();
460 
461       /* FIXME: Where is the best place for this? In interface or here? */
462       lobbyData[ i ].hInformOnAppStart = 0;
463       lobbyData[ i ].hInformOnAppDeath = 0;
464       lobbyData[ i ].hInformOnSettingRead = 0;
465 
466       DPLAYX_ReleaseSemaphore();
467       return TRUE;
468     }
469   }
470 
471   ERR( "No empty lobbies\n" );
472 
473   DPLAYX_ReleaseSemaphore();
474   return FALSE;
475 }
476 
477 /* I'm not sure when I'm going to need this, but here it is */
478 BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID )
479 {
480   UINT i;
481 
482   DPLAYX_AcquireSemaphore();
483 
484   /* Find an empty space in the list and insert the data */
485   for( i=0; i < numSupportedLobbies; i++ )
486   {
487     if( lobbyData[ i ].dwAppID == dwAppID )
488     {
489       /* FIXME: Should free up anything unused. Tisk tisk :0 */
490       /* Mark this entry unused */
491       TRACE( "Marking lobbyData[%u] unused\n", i );
492       DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
493 
494       DPLAYX_ReleaseSemaphore();
495       return TRUE;
496     }
497   }
498 
499   DPLAYX_ReleaseSemaphore();
500   ERR( "Unable to find global entry for application\n" );
501   return FALSE;
502 }
503 
504 BOOL DPLAYX_SetLobbyHandles( DWORD dwAppID,
505                              HANDLE hStart, HANDLE hDeath, HANDLE hConnRead )
506 {
507   LPDPLAYX_LOBBYDATA lpLData;
508 
509   /* Need to explicitly give lobby application. Can't set for yourself */
510   if( dwAppID == 0 )
511   {
512     return FALSE;
513   }
514 
515   DPLAYX_AcquireSemaphore();
516 
517   if( !DPLAYX_IsAppIdLobbied( dwAppID, &lpLData ) )
518   {
519     DPLAYX_ReleaseSemaphore();
520     return FALSE;
521   }
522 
523   lpLData->hInformOnAppStart    = hStart;
524   lpLData->hInformOnAppDeath    = hDeath;
525   lpLData->hInformOnSettingRead = hConnRead;
526 
527   DPLAYX_ReleaseSemaphore();
528 
529   return TRUE;
530 }
531 
532 static BOOL DPLAYX_GetThisLobbyHandles( LPHANDLE lphStart,
533                                         LPHANDLE lphDeath,
534                                         LPHANDLE lphConnRead,
535                                         BOOL     bClearSetHandles )
536 {
537   LPDPLAYX_LOBBYDATA lpLData;
538 
539   DPLAYX_AcquireSemaphore();
540 
541   if( !DPLAYX_IsAppIdLobbied( 0, &lpLData ) )
542   {
543     DPLAYX_ReleaseSemaphore();
544     return FALSE;
545   }
546 
547   if( lphStart != NULL )
548   {
549     if( lpLData->hInformOnAppStart == 0 )
550     {
551       DPLAYX_ReleaseSemaphore();
552       return FALSE;
553     }
554 
555     *lphStart = lpLData->hInformOnAppStart;
556 
557     if( bClearSetHandles )
558     {
559       CloseHandle( lpLData->hInformOnAppStart );
560       lpLData->hInformOnAppStart = 0;
561     }
562   }
563 
564   if( lphDeath != NULL )
565   {
566     if( lpLData->hInformOnAppDeath == 0 )
567     {
568       DPLAYX_ReleaseSemaphore();
569       return FALSE;
570     }
571 
572     *lphDeath = lpLData->hInformOnAppDeath;
573 
574     if( bClearSetHandles )
575     {
576       CloseHandle( lpLData->hInformOnAppDeath );
577       lpLData->hInformOnAppDeath = 0;
578     }
579   }
580 
581   if( lphConnRead != NULL )
582   {
583     if( lpLData->hInformOnSettingRead == 0 )
584     {
585       DPLAYX_ReleaseSemaphore();
586       return FALSE;
587     }
588 
589     *lphConnRead = lpLData->hInformOnSettingRead;
590 
591     if( bClearSetHandles )
592     {
593       CloseHandle( lpLData->hInformOnSettingRead );
594       lpLData->hInformOnSettingRead = 0;
595     }
596   }
597 
598   DPLAYX_ReleaseSemaphore();
599 
600   return TRUE;
601 }
602 
603 
604 HRESULT DPLAYX_GetConnectionSettingsA
605 ( DWORD dwAppID,
606   LPVOID lpData,
607   LPDWORD lpdwDataSize )
608 {
609   LPDPLAYX_LOBBYDATA lpDplData;
610   DWORD              dwRequiredDataSize = 0;
611   HANDLE             hInformOnSettingRead;
612 
613   DPLAYX_AcquireSemaphore();
614 
615   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
616   {
617     DPLAYX_ReleaseSemaphore();
618 
619     TRACE( "Application 0x%08x is not lobbied\n", dwAppID );
620     return DPERR_NOTLOBBIED;
621   }
622 
623   dwRequiredDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn );
624 
625   /* Do they want to know the required buffer size or is the provided buffer
626    * big enough?
627    */
628   if ( ( lpData == NULL ) ||
629        ( *lpdwDataSize < dwRequiredDataSize )
630      )
631   {
632     DPLAYX_ReleaseSemaphore();
633 
634     *lpdwDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn );
635 
636     return DPERR_BUFFERTOOSMALL;
637   }
638 
639   DPLAYX_CopyConnStructA( (LPDPLCONNECTION)lpData, lpDplData->lpConn );
640 
641   DPLAYX_ReleaseSemaphore();
642 
643   /* They have gotten the information - signal the event if required */
644   if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) &&
645       hInformOnSettingRead
646     )
647   {
648     BOOL bSuccess;
649     bSuccess = SetEvent( hInformOnSettingRead );
650     TRACE( "Signalling setting read event %p %s\n",
651              hInformOnSettingRead, bSuccess ? "succeed" : "failed" );
652 
653     /* Close out handle */
654     DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE );
655   }
656 
657   return DP_OK;
658 }
659 
660 /* Assumption: Enough contiguous space was allocated at dest */
661 void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, const DPLCONNECTION *src )
662 {
663   BYTE* lpStartOfFreeSpace;
664 
665   *dest = *src;
666 
667   lpStartOfFreeSpace = ((BYTE*)dest) + sizeof( DPLCONNECTION );
668 
669   /* Copy the LPDPSESSIONDESC2 structure if it exists */
670   if( src->lpSessionDesc )
671   {
672     dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
673     lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
674     *dest->lpSessionDesc = *src->lpSessionDesc;
675 
676     /* Session names may or may not exist */
677     if( src->lpSessionDesc->u1.lpszSessionNameA )
678     {
679       strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->u1.lpszSessionNameA );
680       dest->lpSessionDesc->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
681       lpStartOfFreeSpace +=
682         strlen( dest->lpSessionDesc->u1.lpszSessionNameA ) + 1;
683     }
684 
685     if( src->lpSessionDesc->u2.lpszPasswordA )
686     {
687       strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->u2.lpszPasswordA );
688       dest->lpSessionDesc->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
689       lpStartOfFreeSpace +=
690         strlen( dest->lpSessionDesc->u2.lpszPasswordA ) + 1;
691     }
692   }
693 
694   /* DPNAME structure is optional */
695   if( src->lpPlayerName )
696   {
697     dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
698     lpStartOfFreeSpace += sizeof( DPNAME );
699     *dest->lpPlayerName = *src->lpPlayerName;
700 
701     if( src->lpPlayerName->u1.lpszShortNameA )
702     {
703       strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->u1.lpszShortNameA );
704       dest->lpPlayerName->u1.lpszShortNameA = (LPSTR)lpStartOfFreeSpace;
705       lpStartOfFreeSpace +=
706         strlen( dest->lpPlayerName->u1.lpszShortNameA ) + 1;
707     }
708 
709     if( src->lpPlayerName->u2.lpszLongNameA )
710     {
711       strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->u2.lpszLongNameA );
712       dest->lpPlayerName->u2.lpszLongNameA = (LPSTR)lpStartOfFreeSpace;
713       lpStartOfFreeSpace +=
714         strlen( (LPSTR)dest->lpPlayerName->u2.lpszLongName ) + 1 ;
715     }
716 
717   }
718 
719   /* Copy address if it exists */
720   if( src->lpAddress )
721   {
722     dest->lpAddress = (LPVOID)lpStartOfFreeSpace;
723     CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );
724     /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */
725   }
726 }
727 
728 HRESULT DPLAYX_GetConnectionSettingsW
729 ( DWORD dwAppID,
730   LPVOID lpData,
731   LPDWORD lpdwDataSize )
732 {
733   LPDPLAYX_LOBBYDATA lpDplData;
734   DWORD              dwRequiredDataSize = 0;
735   HANDLE             hInformOnSettingRead;
736 
737   DPLAYX_AcquireSemaphore();
738 
739   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
740   {
741     DPLAYX_ReleaseSemaphore();
742     return DPERR_NOTLOBBIED;
743   }
744 
745   dwRequiredDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn );
746 
747   /* Do they want to know the required buffer size or is the provided buffer
748    * big enough?
749    */
750   if ( ( lpData == NULL ) ||
751        ( *lpdwDataSize < dwRequiredDataSize )
752      )
753   {
754     DPLAYX_ReleaseSemaphore();
755 
756     *lpdwDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn );
757 
758     return DPERR_BUFFERTOOSMALL;
759   }
760 
761   DPLAYX_CopyConnStructW( (LPDPLCONNECTION)lpData, lpDplData->lpConn );
762 
763   DPLAYX_ReleaseSemaphore();
764 
765   /* They have gotten the information - signal the event if required */
766   if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) &&
767       hInformOnSettingRead
768     )
769   {
770     BOOL bSuccess;
771     bSuccess = SetEvent( hInformOnSettingRead );
772     TRACE( "Signalling setting read event %p %s\n",
773              hInformOnSettingRead, bSuccess ? "succeed" : "failed" );
774 
775     /* Close out handle */
776     DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE );
777   }
778 
779   return DP_OK;
780 }
781 
782 /* Assumption: Enough contiguous space was allocated at dest */
783 void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, const DPLCONNECTION *src )
784 {
785   BYTE*              lpStartOfFreeSpace;
786 
787   *dest = *src;
788 
789   lpStartOfFreeSpace = ( (BYTE*)dest) + sizeof( DPLCONNECTION );
790 
791   /* Copy the LPDPSESSIONDESC2 structure if it exists */
792   if( src->lpSessionDesc )
793   {
794     dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
795     lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
796     *dest->lpSessionDesc = *src->lpSessionDesc;
797 
798     /* Session names may or may not exist */
799     if( src->lpSessionDesc->u1.lpszSessionName )
800     {
801       strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpSessionDesc->u1.lpszSessionName );
802       dest->lpSessionDesc->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
803       lpStartOfFreeSpace +=  sizeof(WCHAR) *
804         ( strlenW( dest->lpSessionDesc->u1.lpszSessionName ) + 1 );
805     }
806 
807     if( src->lpSessionDesc->u2.lpszPassword )
808     {
809       strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpSessionDesc->u2.lpszPassword );
810       dest->lpSessionDesc->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
811       lpStartOfFreeSpace +=  sizeof(WCHAR) *
812         ( strlenW( dest->lpSessionDesc->u2.lpszPassword ) + 1 );
813     }
814   }
815 
816   /* DPNAME structure is optional */
817   if( src->lpPlayerName )
818   {
819     dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
820     lpStartOfFreeSpace += sizeof( DPNAME );
821     *dest->lpPlayerName = *src->lpPlayerName;
822 
823     if( src->lpPlayerName->u1.lpszShortName )
824     {
825       strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->u1.lpszShortName );
826       dest->lpPlayerName->u1.lpszShortName = (LPWSTR)lpStartOfFreeSpace;
827       lpStartOfFreeSpace +=  sizeof(WCHAR) *
828         ( strlenW( dest->lpPlayerName->u1.lpszShortName ) + 1 );
829     }
830 
831     if( src->lpPlayerName->u2.lpszLongName )
832     {
833       strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->u2.lpszLongName );
834       dest->lpPlayerName->u2.lpszLongName = (LPWSTR)lpStartOfFreeSpace;
835       lpStartOfFreeSpace +=  sizeof(WCHAR) *
836         ( strlenW( dest->lpPlayerName->u2.lpszLongName ) + 1 );
837     }
838 
839   }
840 
841   /* Copy address if it exists */
842   if( src->lpAddress )
843   {
844     dest->lpAddress = (LPVOID)lpStartOfFreeSpace;
845     CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );
846     /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */
847   }
848 
849 }
850 
851 /* Store the structure into the shared data structure. Ensure that allocs for
852  * variable length strings come from the shared data structure.
853  * FIXME: We need to free information as well.
854  */
855 HRESULT DPLAYX_SetConnectionSettingsA
856 ( DWORD dwFlags,
857   DWORD dwAppID,
858   const DPLCONNECTION *lpConn )
859 {
860   LPDPLAYX_LOBBYDATA lpDplData;
861 
862   /* Parameter check */
863   if( dwFlags || !lpConn )
864   {
865     ERR("invalid parameters.\n");
866     return DPERR_INVALIDPARAMS;
867   }
868 
869   /* Store information */
870   if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
871   {
872     ERR(": old/new DPLCONNECTION type? Size=%08x\n", lpConn->dwSize );
873 
874     return DPERR_INVALIDPARAMS;
875   }
876 
877   DPLAYX_AcquireSemaphore();
878 
879   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
880   {
881     DPLAYX_ReleaseSemaphore();
882 
883     return DPERR_NOTLOBBIED;
884   }
885 
886   if(  (!lpConn->lpSessionDesc ) ||
887        ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
888     )
889   {
890     DPLAYX_ReleaseSemaphore();
891 
892     ERR("DPSESSIONDESC passed in? Size=%u\n", lpConn->lpSessionDesc->dwSize );
893 
894     return DPERR_INVALIDPARAMS;
895   }
896 
897   /* Free the existing memory */
898   DPLAYX_PrivHeapFree( lpDplData->lpConn );
899 
900   lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
901                                             DPLAYX_SizeOfLobbyDataA( lpConn ) );
902 
903   DPLAYX_CopyConnStructA( lpDplData->lpConn, lpConn );
904 
905 
906   DPLAYX_ReleaseSemaphore();
907 
908   /* FIXME: Send a message - I think */
909 
910   return DP_OK;
911 }
912 
913 /* Store the structure into the shared data structure. Ensure that allocs for
914  * variable length strings come from the shared data structure.
915  * FIXME: We need to free information as well
916  */
917 HRESULT DPLAYX_SetConnectionSettingsW
918 ( DWORD dwFlags,
919   DWORD dwAppID,
920   const DPLCONNECTION *lpConn )
921 {
922   LPDPLAYX_LOBBYDATA lpDplData;
923 
924   /* Parameter check */
925   if( dwFlags || !lpConn )
926   {
927     ERR("invalid parameters.\n");
928     return DPERR_INVALIDPARAMS;
929   }
930 
931   /* Store information */
932   if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
933   {
934     ERR(": old/new DPLCONNECTION type? Size=%u\n", lpConn->dwSize );
935 
936     return DPERR_INVALIDPARAMS;
937   }
938 
939   DPLAYX_AcquireSemaphore();
940 
941   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
942   {
943     DPLAYX_ReleaseSemaphore();
944 
945     return DPERR_NOTLOBBIED;
946   }
947 
948   /* Free the existing memory */
949   DPLAYX_PrivHeapFree( lpDplData->lpConn );
950 
951   lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
952                                             DPLAYX_SizeOfLobbyDataW( lpConn ) );
953 
954   DPLAYX_CopyConnStructW( lpDplData->lpConn, lpConn );
955 
956 
957   DPLAYX_ReleaseSemaphore();
958 
959   /* FIXME: Send a message - I think */
960 
961   return DP_OK;
962 }
963 
964 DWORD DPLAYX_SizeOfLobbyDataA( const DPLCONNECTION *lpConn )
965 {
966