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