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