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