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