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