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