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