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