shlwapi/tests: Fix some failures on XP and W2K3.
[wine/multimedia.git] / dlls / dplayx / dplayx_global.c
blobfc72dce9140528802990874a71d885ee6bc48c10
1 /* dplayx.dll global data implementation.
3 * Copyright 1999,2000 - Peter Hunnisett
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.
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.
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
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.
32 #include <stdarg.h>
33 #include <string.h>
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
37 #include "wine/debug.h"
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winerror.h"
41 #include "wine/unicode.h"
43 #include "wingdi.h"
44 #include "winuser.h"
46 #include "dplayx_global.h"
47 #include "dplayx_messages.h" /* For CreateMessageReceptionThread only */
49 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
51 /* FIXME: Need to do all that fun other dll referencing type of stuff */
53 /* Static data for all processes */
54 static const char lpszDplayxSemaName[] = "WINE_DPLAYX_SM";
55 static HANDLE hDplayxSema;
57 static const char lpszDplayxFileMapping[] = "WINE_DPLAYX_FM";
58 static HANDLE hDplayxSharedMem;
60 static LPVOID lpSharedStaticData = NULL;
63 #define DPLAYX_AcquireSemaphore() TRACE( "Waiting for DPLAYX semaphore\n" ); \
64 WaitForSingleObject( hDplayxSema, INFINITE );\
65 TRACE( "Through wait\n" )
67 #define DPLAYX_ReleaseSemaphore() ReleaseSemaphore( hDplayxSema, 1, NULL ); \
68 TRACE( "DPLAYX Semaphore released\n" ) /* FIXME: Is this correct? */
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 )
77 /* FIXME: Is there no easier way? */
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)
84 typedef struct
86 DWORD used;
87 DWORD data[dwBlockSize-sizeof(DWORD)];
88 } DPLAYX_MEM_SLICE;
90 static DPLAYX_MEM_SLICE* lpMemArea;
92 void DPLAYX_PrivHeapFree( LPVOID addr );
93 void DPLAYX_PrivHeapFree( LPVOID addr )
95 LPVOID lpAddrStart;
96 DWORD dwBlockUsed;
98 /* Handle getting passed a NULL */
99 if( addr == NULL )
101 return;
104 lpAddrStart = (char*)addr - sizeof(DWORD); /* Find block header */
105 dwBlockUsed = ((BYTE*)lpAddrStart - (BYTE*)lpMemArea)/dwBlockSize;
107 lpMemArea[ dwBlockUsed ].used = 0;
110 /* FIXME: This should be static, but is being used for a hack right now */
111 LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size );
112 LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size )
114 LPVOID lpvArea = NULL;
115 UINT uBlockUsed;
117 if( size > (dwBlockSize - sizeof(DWORD)) )
119 FIXME( "Size exceeded. Request of 0x%08x\n", size );
120 size = dwBlockSize - sizeof(DWORD);
123 /* Find blank area */
124 uBlockUsed = 0;
125 while( ( lpMemArea[ uBlockUsed ].used != 0 ) && ( uBlockUsed <= dwMaxBlock ) ) { uBlockUsed++; }
127 if( uBlockUsed <= dwMaxBlock )
129 /* Set the area used */
130 lpMemArea[ uBlockUsed ].used = 1;
131 lpvArea = lpMemArea[ uBlockUsed ].data;
133 else
135 ERR( "No free block found\n" );
136 return NULL;
139 if( flags & HEAP_ZERO_MEMORY )
141 ZeroMemory( lpvArea, size );
144 return lpvArea;
147 LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str );
148 LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str )
150 LPSTR p = DPLAYX_PrivHeapAlloc( flags, strlen(str) + 1 );
151 if(p) {
152 strcpy( p, str );
154 return p;
157 LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str );
158 LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str )
160 INT len = strlenW(str) + 1;
161 LPWSTR p = DPLAYX_PrivHeapAlloc( flags, len * sizeof(WCHAR) );
162 if(p) {
163 strcpyW( p, str );
165 return p;
169 enum { numSupportedLobbies = 32, numSupportedSessions = 32 };
170 typedef struct tagDPLAYX_LOBBYDATA
172 /* Points to lpConn + block of contiguous extra memory for dynamic parts
173 * of the struct directly following
175 LPDPLCONNECTION lpConn;
177 /* Information for dplobby interfaces */
178 DWORD dwAppID;
179 DWORD dwAppLaunchedFromID;
181 /* Should this lobby app send messages to creator at important life
182 * stages
184 HANDLE hInformOnAppStart;
185 HANDLE hInformOnAppDeath;
186 HANDLE hInformOnSettingRead;
188 /* Sundries */
189 BOOL bWaitForConnectionSettings;
190 DWORD dwLobbyMsgThreadId;
193 } DPLAYX_LOBBYDATA, *LPDPLAYX_LOBBYDATA;
195 static DPLAYX_LOBBYDATA* lobbyData = NULL;
196 /* static DPLAYX_LOBBYDATA lobbyData[ numSupportedLobbies ]; */
198 static DPSESSIONDESC2* sessionData = NULL;
199 /* static DPSESSIONDESC2* sessionData[ numSupportedSessions ]; */
201 /* Function prototypes */
202 static DWORD DPLAYX_SizeOfLobbyDataA( const DPLCONNECTION *lpDplData );
203 static DWORD DPLAYX_SizeOfLobbyDataW( const DPLCONNECTION *lpDplData );
204 static void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, const DPLCONNECTION *src );
205 static void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, const DPLCONNECTION *src );
206 static BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppId, LPDPLAYX_LOBBYDATA* dplData );
207 static void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData );
208 static BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2 lpSessionDest,
209 LPCDPSESSIONDESC2 lpSessionSrc );
210 static BOOL DPLAYX_GetThisLobbyHandles( LPHANDLE lphStart, LPHANDLE lphDeath,
211 LPHANDLE lphConnRead, BOOL bClearSetHandles );
215 /***************************************************************************
216 * Called to initialize the global data. This will only be used on the
217 * loading of the dll
218 ***************************************************************************/
219 BOOL DPLAYX_ConstructData(void)
221 SECURITY_ATTRIBUTES s_attrib;
222 BOOL bInitializeSharedMemory = FALSE;
223 LPVOID lpDesiredMemoryMapStart = (LPVOID)0x50000000;
224 HANDLE hInformOnStart;
226 TRACE( "DPLAYX dll loaded - construct called\n" );
228 /* Create a semaphore to block access to DPLAYX global data structs */
230 s_attrib.bInheritHandle = TRUE;
231 s_attrib.lpSecurityDescriptor = NULL;
232 s_attrib.nLength = sizeof(s_attrib);
234 hDplayxSema = CreateSemaphoreA( &s_attrib, 0, 1, lpszDplayxSemaName );
236 /* First instance creates the semaphore. Others just use it */
237 if( GetLastError() == ERROR_SUCCESS )
239 TRACE( "Semaphore %p created\n", hDplayxSema );
241 /* The semaphore creator will also build the shared memory */
242 bInitializeSharedMemory = TRUE;
244 else if ( GetLastError() == ERROR_ALREADY_EXISTS )
246 TRACE( "Found semaphore handle %p\n", hDplayxSema );
247 DPLAYX_AcquireSemaphore();
249 else
251 ERR( ": semaphore error %d\n", GetLastError() );
252 return FALSE;
255 SetLastError( ERROR_SUCCESS );
257 hDplayxSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE,
258 &s_attrib,
259 PAGE_READWRITE | SEC_COMMIT,
261 dwTotalSharedSize,
262 lpszDplayxFileMapping );
264 if( GetLastError() == ERROR_SUCCESS )
266 TRACE( "File mapped %p created\n", hDplayxSharedMem );
268 else if ( GetLastError() == ERROR_ALREADY_EXISTS )
270 TRACE( "Found FileMapping handle %p\n", hDplayxSharedMem );
272 else
274 ERR( ": unable to create shared memory (%d)\n", GetLastError() );
275 DPLAYX_ReleaseSemaphore();
276 return FALSE;
279 lpSharedStaticData = MapViewOfFileEx( hDplayxSharedMem,
280 FILE_MAP_WRITE,
281 0, 0, 0, lpDesiredMemoryMapStart );
283 if( lpSharedStaticData == NULL )
285 ERR( ": unable to map static data into process memory space (%d)\n",
286 GetLastError() );
287 DPLAYX_ReleaseSemaphore();
288 return FALSE;
290 else
292 if( lpDesiredMemoryMapStart == lpSharedStaticData )
294 TRACE( "File mapped to %p\n", lpSharedStaticData );
296 else
298 /* Presently the shared data structures use pointers. If the
299 * files are no mapped into the same area, the pointers will no
300 * longer make any sense :(
301 * FIXME: In the future make the shared data structures have some
302 * sort of fixup to make them independent between data spaces.
303 * This will also require a rework of the session data stuff.
305 ERR( "File mapped to %p (not %p). Expect failure\n",
306 lpSharedStaticData, lpDesiredMemoryMapStart );
310 /* Dynamic area starts just after the static area */
311 lpMemArea = (LPVOID)((BYTE*)lpSharedStaticData + dwStaticSharedSize);
313 /* FIXME: Crude hack */
314 lobbyData = (DPLAYX_LOBBYDATA*)lpSharedStaticData;
315 sessionData = (DPSESSIONDESC2*)((BYTE*)lpSharedStaticData + (dwStaticSharedSize/2));
317 /* Initialize shared data segments. */
318 if( bInitializeSharedMemory )
320 UINT i;
322 TRACE( "Initializing shared memory\n" );
324 /* Set all lobbies to be "empty" */
325 for( i=0; i < numSupportedLobbies; i++ )
327 DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
330 /* Set all sessions to be "empty" */
331 for( i=0; i < numSupportedSessions; i++ )
333 sessionData[i].dwSize = 0;
336 /* Zero out the dynamic area */
337 ZeroMemory( lpMemArea, dwDynamicSharedSize );
339 /* Just for fun sync the whole data area */
340 FlushViewOfFile( lpSharedStaticData, dwTotalSharedSize );
343 DPLAYX_ReleaseSemaphore();
345 /* Everything was created correctly. Signal the lobby client that
346 * we started up correctly
348 if( DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, FALSE ) &&
349 hInformOnStart
352 BOOL bSuccess;
353 bSuccess = SetEvent( hInformOnStart );
354 TRACE( "Signalling lobby app start event %p %s\n",
355 hInformOnStart, bSuccess ? "succeed" : "failed" );
357 /* Close out handle */
358 DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, TRUE );
361 return TRUE;
364 /***************************************************************************
365 * Called to destroy all global data. This will only be used on the
366 * unloading of the dll
367 ***************************************************************************/
368 BOOL DPLAYX_DestructData(void)
370 HANDLE hInformOnDeath;
372 TRACE( "DPLAYX dll unloaded - destruct called\n" );
374 /* If required, inform that this app is dying */
375 if( DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, FALSE ) &&
376 hInformOnDeath
379 BOOL bSuccess;
380 bSuccess = SetEvent( hInformOnDeath );
381 TRACE( "Signalling lobby app death event %p %s\n",
382 hInformOnDeath, bSuccess ? "succeed" : "failed" );
384 /* Close out handle */
385 DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, TRUE );
388 /* DO CLEAN UP (LAST) */
390 /* Delete the semaphore */
391 CloseHandle( hDplayxSema );
393 /* Delete shared memory file mapping */
394 UnmapViewOfFile( lpSharedStaticData );
395 CloseHandle( hDplayxSharedMem );
397 return FALSE;
401 void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData )
403 ZeroMemory( lpData, sizeof( *lpData ) );
406 /* NOTE: This must be called with the semaphore acquired.
407 * TRUE/FALSE with a pointer to it's data returned. Pointer data is
408 * is only valid if TRUE is returned.
410 BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppID, LPDPLAYX_LOBBYDATA* lplpDplData )
412 UINT i;
414 *lplpDplData = NULL;
416 if( dwAppID == 0 )
418 dwAppID = GetCurrentProcessId();
419 TRACE( "Translated dwAppID == 0 into 0x%08x\n", dwAppID );
422 for( i=0; i < numSupportedLobbies; i++ )
424 if( lobbyData[ i ].dwAppID == dwAppID )
426 /* This process is lobbied */
427 TRACE( "Found 0x%08x @ %u\n", dwAppID, i );
428 *lplpDplData = &lobbyData[ i ];
429 return TRUE;
433 return FALSE;
436 /* Reserve a spot for the new application. TRUE means success and FALSE failure. */
437 BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID )
439 UINT i;
441 /* 0 is the marker for unused application data slots */
442 if( dwAppID == 0 )
444 return FALSE;
447 DPLAYX_AcquireSemaphore();
449 /* Find an empty space in the list and insert the data */
450 for( i=0; i < numSupportedLobbies; i++ )
452 if( lobbyData[ i ].dwAppID == 0 )
454 /* This process is now lobbied */
455 TRACE( "Setting lobbyData[%u] for (0x%08x,0x%08x)\n",
456 i, dwAppID, GetCurrentProcessId() );
458 lobbyData[ i ].dwAppID = dwAppID;
459 lobbyData[ i ].dwAppLaunchedFromID = GetCurrentProcessId();
461 /* FIXME: Where is the best place for this? In interface or here? */
462 lobbyData[ i ].hInformOnAppStart = 0;
463 lobbyData[ i ].hInformOnAppDeath = 0;
464 lobbyData[ i ].hInformOnSettingRead = 0;
466 DPLAYX_ReleaseSemaphore();
467 return TRUE;
471 ERR( "No empty lobbies\n" );
473 DPLAYX_ReleaseSemaphore();
474 return FALSE;
477 /* I'm not sure when I'm going to need this, but here it is */
478 BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID )
480 UINT i;
482 DPLAYX_AcquireSemaphore();
484 /* Find an empty space in the list and insert the data */
485 for( i=0; i < numSupportedLobbies; i++ )
487 if( lobbyData[ i ].dwAppID == dwAppID )
489 /* FIXME: Should free up anything unused. Tisk tisk :0 */
490 /* Mark this entry unused */
491 TRACE( "Marking lobbyData[%u] unused\n", i );
492 DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
494 DPLAYX_ReleaseSemaphore();
495 return TRUE;
499 DPLAYX_ReleaseSemaphore();
500 ERR( "Unable to find global entry for application\n" );
501 return FALSE;
504 BOOL DPLAYX_SetLobbyHandles( DWORD dwAppID,
505 HANDLE hStart, HANDLE hDeath, HANDLE hConnRead )
507 LPDPLAYX_LOBBYDATA lpLData;
509 /* Need to explicitly give lobby application. Can't set for yourself */
510 if( dwAppID == 0 )
512 return FALSE;
515 DPLAYX_AcquireSemaphore();
517 if( !DPLAYX_IsAppIdLobbied( dwAppID, &lpLData ) )
519 DPLAYX_ReleaseSemaphore();
520 return FALSE;
523 lpLData->hInformOnAppStart = hStart;
524 lpLData->hInformOnAppDeath = hDeath;
525 lpLData->hInformOnSettingRead = hConnRead;
527 DPLAYX_ReleaseSemaphore();
529 return TRUE;
532 static BOOL DPLAYX_GetThisLobbyHandles( LPHANDLE lphStart,
533 LPHANDLE lphDeath,
534 LPHANDLE lphConnRead,
535 BOOL bClearSetHandles )
537 LPDPLAYX_LOBBYDATA lpLData;
539 DPLAYX_AcquireSemaphore();
541 if( !DPLAYX_IsAppIdLobbied( 0, &lpLData ) )
543 DPLAYX_ReleaseSemaphore();
544 return FALSE;
547 if( lphStart != NULL )
549 if( lpLData->hInformOnAppStart == 0 )
551 DPLAYX_ReleaseSemaphore();
552 return FALSE;
555 *lphStart = lpLData->hInformOnAppStart;
557 if( bClearSetHandles )
559 CloseHandle( lpLData->hInformOnAppStart );
560 lpLData->hInformOnAppStart = 0;
564 if( lphDeath != NULL )
566 if( lpLData->hInformOnAppDeath == 0 )
568 DPLAYX_ReleaseSemaphore();
569 return FALSE;
572 *lphDeath = lpLData->hInformOnAppDeath;
574 if( bClearSetHandles )
576 CloseHandle( lpLData->hInformOnAppDeath );
577 lpLData->hInformOnAppDeath = 0;
581 if( lphConnRead != NULL )
583 if( lpLData->hInformOnSettingRead == 0 )
585 DPLAYX_ReleaseSemaphore();
586 return FALSE;
589 *lphConnRead = lpLData->hInformOnSettingRead;
591 if( bClearSetHandles )
593 CloseHandle( lpLData->hInformOnSettingRead );
594 lpLData->hInformOnSettingRead = 0;
598 DPLAYX_ReleaseSemaphore();
600 return TRUE;
604 HRESULT DPLAYX_GetConnectionSettingsA
605 ( DWORD dwAppID,
606 LPVOID lpData,
607 LPDWORD lpdwDataSize )
609 LPDPLAYX_LOBBYDATA lpDplData;
610 DWORD dwRequiredDataSize = 0;
611 HANDLE hInformOnSettingRead;
613 DPLAYX_AcquireSemaphore();
615 if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
617 DPLAYX_ReleaseSemaphore();
619 TRACE( "Application 0x%08x is not lobbied\n", dwAppID );
620 return DPERR_NOTLOBBIED;
623 dwRequiredDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn );
625 /* Do they want to know the required buffer size or is the provided buffer
626 * big enough?
628 if ( ( lpData == NULL ) ||
629 ( *lpdwDataSize < dwRequiredDataSize )
632 DPLAYX_ReleaseSemaphore();
634 *lpdwDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn );
636 return DPERR_BUFFERTOOSMALL;
639 DPLAYX_CopyConnStructA( (LPDPLCONNECTION)lpData, lpDplData->lpConn );
641 DPLAYX_ReleaseSemaphore();
643 /* They have gotten the information - signal the event if required */
644 if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) &&
645 hInformOnSettingRead
648 BOOL bSuccess;
649 bSuccess = SetEvent( hInformOnSettingRead );
650 TRACE( "Signalling setting read event %p %s\n",
651 hInformOnSettingRead, bSuccess ? "succeed" : "failed" );
653 /* Close out handle */
654 DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE );
657 return DP_OK;
660 /* Assumption: Enough contiguous space was allocated at dest */
661 void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, const DPLCONNECTION *src )
663 BYTE* lpStartOfFreeSpace;
665 *dest = *src;
667 lpStartOfFreeSpace = ((BYTE*)dest) + sizeof( DPLCONNECTION );
669 /* Copy the LPDPSESSIONDESC2 structure if it exists */
670 if( src->lpSessionDesc )
672 dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
673 lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
674 *dest->lpSessionDesc = *src->lpSessionDesc;
676 /* Session names may or may not exist */
677 if( src->lpSessionDesc->u1.lpszSessionNameA )
679 strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->u1.lpszSessionNameA );
680 dest->lpSessionDesc->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
681 lpStartOfFreeSpace +=
682 strlen( dest->lpSessionDesc->u1.lpszSessionNameA ) + 1;
685 if( src->lpSessionDesc->u2.lpszPasswordA )
687 strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->u2.lpszPasswordA );
688 dest->lpSessionDesc->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
689 lpStartOfFreeSpace +=
690 strlen( dest->lpSessionDesc->u2.lpszPasswordA ) + 1;
694 /* DPNAME structure is optional */
695 if( src->lpPlayerName )
697 dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
698 lpStartOfFreeSpace += sizeof( DPNAME );
699 *dest->lpPlayerName = *src->lpPlayerName;
701 if( src->lpPlayerName->u1.lpszShortNameA )
703 strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->u1.lpszShortNameA );
704 dest->lpPlayerName->u1.lpszShortNameA = (LPSTR)lpStartOfFreeSpace;
705 lpStartOfFreeSpace +=
706 strlen( dest->lpPlayerName->u1.lpszShortNameA ) + 1;
709 if( src->lpPlayerName->u2.lpszLongNameA )
711 strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->u2.lpszLongNameA );
712 dest->lpPlayerName->u2.lpszLongNameA = (LPSTR)lpStartOfFreeSpace;
713 lpStartOfFreeSpace +=
714 strlen( (LPSTR)dest->lpPlayerName->u2.lpszLongName ) + 1 ;
719 /* Copy address if it exists */
720 if( src->lpAddress )
722 dest->lpAddress = (LPVOID)lpStartOfFreeSpace;
723 CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );
724 /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */
728 HRESULT DPLAYX_GetConnectionSettingsW
729 ( DWORD dwAppID,
730 LPVOID lpData,
731 LPDWORD lpdwDataSize )
733 LPDPLAYX_LOBBYDATA lpDplData;
734 DWORD dwRequiredDataSize = 0;
735 HANDLE hInformOnSettingRead;
737 DPLAYX_AcquireSemaphore();
739 if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
741 DPLAYX_ReleaseSemaphore();
742 return DPERR_NOTLOBBIED;
745 dwRequiredDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn );
747 /* Do they want to know the required buffer size or is the provided buffer
748 * big enough?
750 if ( ( lpData == NULL ) ||
751 ( *lpdwDataSize < dwRequiredDataSize )
754 DPLAYX_ReleaseSemaphore();
756 *lpdwDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn );
758 return DPERR_BUFFERTOOSMALL;
761 DPLAYX_CopyConnStructW( (LPDPLCONNECTION)lpData, lpDplData->lpConn );
763 DPLAYX_ReleaseSemaphore();
765 /* They have gotten the information - signal the event if required */
766 if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) &&
767 hInformOnSettingRead
770 BOOL bSuccess;
771 bSuccess = SetEvent( hInformOnSettingRead );
772 TRACE( "Signalling setting read event %p %s\n",
773 hInformOnSettingRead, bSuccess ? "succeed" : "failed" );
775 /* Close out handle */
776 DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE );
779 return DP_OK;
782 /* Assumption: Enough contiguous space was allocated at dest */
783 void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, const DPLCONNECTION *src )
785 BYTE* lpStartOfFreeSpace;
787 *dest = *src;
789 lpStartOfFreeSpace = ( (BYTE*)dest) + sizeof( DPLCONNECTION );
791 /* Copy the LPDPSESSIONDESC2 structure if it exists */
792 if( src->lpSessionDesc )
794 dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
795 lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
796 *dest->lpSessionDesc = *src->lpSessionDesc;
798 /* Session names may or may not exist */
799 if( src->lpSessionDesc->u1.lpszSessionName )
801 strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpSessionDesc->u1.lpszSessionName );
802 dest->lpSessionDesc->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
803 lpStartOfFreeSpace += sizeof(WCHAR) *
804 ( strlenW( dest->lpSessionDesc->u1.lpszSessionName ) + 1 );
807 if( src->lpSessionDesc->u2.lpszPassword )
809 strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpSessionDesc->u2.lpszPassword );
810 dest->lpSessionDesc->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
811 lpStartOfFreeSpace += sizeof(WCHAR) *
812 ( strlenW( dest->lpSessionDesc->u2.lpszPassword ) + 1 );
816 /* DPNAME structure is optional */
817 if( src->lpPlayerName )
819 dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
820 lpStartOfFreeSpace += sizeof( DPNAME );
821 *dest->lpPlayerName = *src->lpPlayerName;
823 if( src->lpPlayerName->u1.lpszShortName )
825 strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->u1.lpszShortName );
826 dest->lpPlayerName->u1.lpszShortName = (LPWSTR)lpStartOfFreeSpace;
827 lpStartOfFreeSpace += sizeof(WCHAR) *
828 ( strlenW( dest->lpPlayerName->u1.lpszShortName ) + 1 );
831 if( src->lpPlayerName->u2.lpszLongName )
833 strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->u2.lpszLongName );
834 dest->lpPlayerName->u2.lpszLongName = (LPWSTR)lpStartOfFreeSpace;
835 lpStartOfFreeSpace += sizeof(WCHAR) *
836 ( strlenW( dest->lpPlayerName->u2.lpszLongName ) + 1 );
841 /* Copy address if it exists */
842 if( src->lpAddress )
844 dest->lpAddress = (LPVOID)lpStartOfFreeSpace;
845 CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );
846 /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */
851 /* Store the structure into the shared data structure. Ensure that allocs for
852 * variable length strings come from the shared data structure.
853 * FIXME: We need to free information as well.
855 HRESULT DPLAYX_SetConnectionSettingsA
856 ( DWORD dwFlags,
857 DWORD dwAppID,
858 const DPLCONNECTION *lpConn )
860 LPDPLAYX_LOBBYDATA lpDplData;
862 /* Parameter check */
863 if( dwFlags || !lpConn )
865 ERR("invalid parameters.\n");
866 return DPERR_INVALIDPARAMS;
869 /* Store information */
870 if( lpConn->dwSize != sizeof(DPLCONNECTION) )
872 ERR(": old/new DPLCONNECTION type? Size=%08x\n", lpConn->dwSize );
874 return DPERR_INVALIDPARAMS;
877 DPLAYX_AcquireSemaphore();
879 if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
881 DPLAYX_ReleaseSemaphore();
883 return DPERR_NOTLOBBIED;
886 if( (!lpConn->lpSessionDesc ) ||
887 ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
890 DPLAYX_ReleaseSemaphore();
892 ERR("DPSESSIONDESC passed in? Size=%u\n",
893 lpConn->lpSessionDesc?lpConn->lpSessionDesc->dwSize:0 );
895 return DPERR_INVALIDPARAMS;
898 /* Free the existing memory */
899 DPLAYX_PrivHeapFree( lpDplData->lpConn );
901 lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
902 DPLAYX_SizeOfLobbyDataA( lpConn ) );
904 DPLAYX_CopyConnStructA( lpDplData->lpConn, lpConn );
907 DPLAYX_ReleaseSemaphore();
909 /* FIXME: Send a message - I think */
911 return DP_OK;
914 /* Store the structure into the shared data structure. Ensure that allocs for
915 * variable length strings come from the shared data structure.
916 * FIXME: We need to free information as well
918 HRESULT DPLAYX_SetConnectionSettingsW
919 ( DWORD dwFlags,
920 DWORD dwAppID,
921 const DPLCONNECTION *lpConn )
923 LPDPLAYX_LOBBYDATA lpDplData;
925 /* Parameter check */
926 if( dwFlags || !lpConn )
928 ERR("invalid parameters.\n");
929 return DPERR_INVALIDPARAMS;
932 /* Store information */
933 if( lpConn->dwSize != sizeof(DPLCONNECTION) )
935 ERR(": old/new DPLCONNECTION type? Size=%u\n", lpConn->dwSize );
937 return DPERR_INVALIDPARAMS;
940 DPLAYX_AcquireSemaphore();
942 if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
944 DPLAYX_ReleaseSemaphore();
946 return DPERR_NOTLOBBIED;
949 /* Free the existing memory */
950 DPLAYX_PrivHeapFree( lpDplData->lpConn );
952 lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
953 DPLAYX_SizeOfLobbyDataW( lpConn ) );
955 DPLAYX_CopyConnStructW( lpDplData->lpConn, lpConn );
958 DPLAYX_ReleaseSemaphore();
960 /* FIXME: Send a message - I think */
962 return DP_OK;
965 DWORD DPLAYX_SizeOfLobbyDataA( const DPLCONNECTION *lpConn )
967 DWORD dwTotalSize = sizeof( DPLCONNECTION );
969 /* Just a safety check */
970 if( lpConn == NULL )
972 ERR( "lpConn is NULL\n" );
973 return 0;
976 if( lpConn->lpSessionDesc != NULL )
978 dwTotalSize += sizeof( DPSESSIONDESC2 );
980 if( lpConn->lpSessionDesc->u1.lpszSessionNameA )
982 dwTotalSize += strlen( lpConn->lpSessionDesc->u1.lpszSessionNameA ) + 1;
985 if( lpConn->lpSessionDesc->u2.lpszPasswordA )
987 dwTotalSize += strlen( lpConn->lpSessionDesc->u2.lpszPasswordA ) + 1;
991 if( lpConn->lpPlayerName != NULL )
993 dwTotalSize += sizeof( DPNAME );
995 if( lpConn->lpPlayerName->u1.lpszShortNameA )
997 dwTotalSize += strlen( lpConn->lpPlayerName->u1.lpszShortNameA ) + 1;
1000 if( lpConn->lpPlayerName->u2.lpszLongNameA )
1002 dwTotalSize += strlen( lpConn->lpPlayerName->u2.lpszLongNameA ) + 1;
1007 dwTotalSize += lpConn->dwAddressSize;
1009 return dwTotalSize;
1012 DWORD DPLAYX_SizeOfLobbyDataW( const DPLCONNECTION *lpConn )
1014 DWORD dwTotalSize = sizeof( DPLCONNECTION );
1016 /* Just a safety check */
1017 if( lpConn == NULL )
1019 ERR( "lpConn is NULL\n" );
1020 return 0;
1023 if( lpConn->lpSessionDesc != NULL )
1025 dwTotalSize += sizeof( DPSESSIONDESC2 );
1027 if( lpConn->lpSessionDesc->u1.lpszSessionName )
1029 dwTotalSize += sizeof( WCHAR ) *
1030 ( strlenW( lpConn->lpSessionDesc->u1.lpszSessionName ) + 1 );
1033 if( lpConn->lpSessionDesc->u2.lpszPassword )
1035 dwTotalSize += sizeof( WCHAR ) *
1036 ( strlenW( lpConn->lpSessionDesc->u2.lpszPassword ) + 1 );
1040 if( lpConn->lpPlayerName != NULL )
1042 dwTotalSize += sizeof( DPNAME );
1044 if( lpConn->lpPlayerName->u1.lpszShortName )
1046 dwTotalSize += sizeof( WCHAR ) *
1047 ( strlenW( lpConn->lpPlayerName->u1.lpszShortName ) + 1 );
1050 if( lpConn->lpPlayerName->u2.lpszLongName )
1052 dwTotalSize += sizeof( WCHAR ) *
1053 ( strlenW( lpConn->lpPlayerName->u2.lpszLongName ) + 1 );
1058 dwTotalSize += lpConn->dwAddressSize;
1060 return dwTotalSize;
1065 static LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateSessionDesc2A( LPCDPSESSIONDESC2 lpSessionSrc )
1067 LPDPSESSIONDESC2 lpSessionDest =
1068 HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpSessionSrc ) );
1069 DPLAYX_CopyIntoSessionDesc2A( lpSessionDest, lpSessionSrc );
1071 return lpSessionDest;
1074 /* Copy an ANSI session desc structure to the given buffer */
1075 BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2 lpSessionDest,
1076 LPCDPSESSIONDESC2 lpSessionSrc )
1078 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
1080 if( lpSessionSrc->u1.lpszSessionNameA )
1082 if ((lpSessionDest->u1.lpszSessionNameA = HeapAlloc( GetProcessHeap(), 0,
1083 strlen(lpSessionSrc->u1.lpszSessionNameA)+1 )))
1084 strcpy( lpSessionDest->u1.lpszSessionNameA, lpSessionSrc->u1.lpszSessionNameA );
1086 if( lpSessionSrc->u2.lpszPasswordA )
1088 if ((lpSessionDest->u2.lpszPasswordA = HeapAlloc( GetProcessHeap(), 0,
1089 strlen(lpSessionSrc->u2.lpszPasswordA)+1 )))
1090 strcpy( lpSessionDest->u2.lpszPasswordA, lpSessionSrc->u2.lpszPasswordA );
1093 return TRUE;
1096 /* Start the index at 0. index will be updated to equal that which should
1097 be passed back into this function for the next element */
1098 LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateLocalSession( UINT* index )
1100 for( ; (*index) < numSupportedSessions; (*index)++ )
1102 if( sessionData[(*index)].dwSize != 0 )
1104 return DPLAYX_CopyAndAllocateSessionDesc2A( &sessionData[(*index)++] );
1108 /* No more sessions */
1109 return NULL;
1112 /* Start the index at 0. index will be updated to equal that which should
1113 be passed back into this function for the next element */
1114 BOOL DPLAYX_CopyLocalSession( UINT* index, LPDPSESSIONDESC2 lpsd )
1116 for( ; (*index) < numSupportedSessions; (*index)++ )
1118 if( sessionData[(*index)].dwSize != 0 )
1120 return DPLAYX_CopyIntoSessionDesc2A( lpsd, &sessionData[(*index)++] );
1124 /* No more sessions */
1125 return FALSE;
1128 void DPLAYX_SetLocalSession( LPCDPSESSIONDESC2 lpsd )
1130 UINT i;
1132 /* FIXME: Is this an error if it exists already? */
1134 /* Crude/wrong implementation for now. Just always add to first empty spot */
1135 for( i=0; i < numSupportedSessions; i++ )
1137 /* Is this one empty? */
1138 if( sessionData[i].dwSize == 0 )
1140 DPLAYX_CopyIntoSessionDesc2A( &sessionData[i], lpsd );
1141 break;
1147 BOOL DPLAYX_WaitForConnectionSettings( BOOL bWait )
1149 LPDPLAYX_LOBBYDATA lpLobbyData;
1151 DPLAYX_AcquireSemaphore();
1153 if( !DPLAYX_IsAppIdLobbied( 0, &lpLobbyData ) )
1155 DPLAYX_ReleaseSemaphore();
1156 return FALSE;
1159 lpLobbyData->bWaitForConnectionSettings = bWait;
1161 DPLAYX_ReleaseSemaphore();
1163 return TRUE;
1166 BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void)
1168 UINT i;
1169 BOOL bFound = FALSE;
1171 DPLAYX_AcquireSemaphore();
1173 for( i=0; i < numSupportedLobbies; i++ )
1175 if( ( lobbyData[ i ].dwAppID != 0 ) && /* lobby initialized */
1176 ( lobbyData[ i ].bWaitForConnectionSettings ) /* Waiting */
1179 bFound = TRUE;
1180 break;
1184 DPLAYX_ReleaseSemaphore();
1186 return bFound;
1189 BOOL DPLAYX_SetLobbyMsgThreadId( DWORD dwAppId, DWORD dwThreadId )
1191 LPDPLAYX_LOBBYDATA lpLobbyData;
1193 DPLAYX_AcquireSemaphore();
1195 if( !DPLAYX_IsAppIdLobbied( dwAppId, &lpLobbyData ) )
1197 DPLAYX_ReleaseSemaphore();
1198 return FALSE;
1201 lpLobbyData->dwLobbyMsgThreadId = dwThreadId;
1203 DPLAYX_ReleaseSemaphore();
1205 return TRUE;
1208 /* NOTE: This is potentially not thread safe. You are not guaranteed to end up
1209 with the correct string printed in the case where the HRESULT is not
1210 known. You will just get the last hr passed in. This can change
1211 over time if this method is used a lot :) */
1212 LPCSTR DPLAYX_HresultToString(HRESULT hr)
1214 static char szTempStr[12];
1216 switch (hr)
1218 case DP_OK:
1219 return "DP_OK";
1220 case DPERR_ALREADYINITIALIZED:
1221 return "DPERR_ALREADYINITIALIZED";
1222 case DPERR_ACCESSDENIED:
1223 return "DPERR_ACCESSDENIED";
1224 case DPERR_ACTIVEPLAYERS:
1225 return "DPERR_ACTIVEPLAYERS";
1226 case DPERR_BUFFERTOOSMALL:
1227 return "DPERR_BUFFERTOOSMALL";
1228 case DPERR_CANTADDPLAYER:
1229 return "DPERR_CANTADDPLAYER";
1230 case DPERR_CANTCREATEGROUP:
1231 return "DPERR_CANTCREATEGROUP";
1232 case DPERR_CANTCREATEPLAYER:
1233 return "DPERR_CANTCREATEPLAYER";
1234 case DPERR_CANTCREATESESSION:
1235 return "DPERR_CANTCREATESESSION";
1236 case DPERR_CAPSNOTAVAILABLEYET:
1237 return "DPERR_CAPSNOTAVAILABLEYET";
1238 case DPERR_EXCEPTION:
1239 return "DPERR_EXCEPTION";
1240 case DPERR_GENERIC:
1241 return "DPERR_GENERIC";
1242 case DPERR_INVALIDFLAGS:
1243 return "DPERR_INVALIDFLAGS";
1244 case DPERR_INVALIDOBJECT:
1245 return "DPERR_INVALIDOBJECT";
1246 case DPERR_INVALIDPARAMS:
1247 return "DPERR_INVALIDPARAMS";
1248 case DPERR_INVALIDPLAYER:
1249 return "DPERR_INVALIDPLAYER";
1250 case DPERR_INVALIDGROUP:
1251 return "DPERR_INVALIDGROUP";
1252 case DPERR_NOCAPS:
1253 return "DPERR_NOCAPS";
1254 case DPERR_NOCONNECTION:
1255 return "DPERR_NOCONNECTION";
1256 case DPERR_OUTOFMEMORY:
1257 return "DPERR_OUTOFMEMORY";
1258 case DPERR_NOMESSAGES:
1259 return "DPERR_NOMESSAGES";
1260 case DPERR_NONAMESERVERFOUND:
1261 return "DPERR_NONAMESERVERFOUND";
1262 case DPERR_NOPLAYERS:
1263 return "DPERR_NOPLAYERS";
1264 case DPERR_NOSESSIONS:
1265 return "DPERR_NOSESSIONS";
1266 case DPERR_PENDING:
1267 return "DPERR_PENDING";
1268 case DPERR_SENDTOOBIG:
1269 return "DPERR_SENDTOOBIG";
1270 case DPERR_TIMEOUT:
1271 return "DPERR_TIMEOUT";
1272 case DPERR_UNAVAILABLE:
1273 return "DPERR_UNAVAILABLE";
1274 case DPERR_UNSUPPORTED:
1275 return "DPERR_UNSUPPORTED";
1276 case DPERR_BUSY:
1277 return "DPERR_BUSY";
1278 case DPERR_USERCANCEL:
1279 return "DPERR_USERCANCEL";
1280 case DPERR_NOINTERFACE:
1281 return "DPERR_NOINTERFACE";
1282 case DPERR_CANNOTCREATESERVER:
1283 return "DPERR_CANNOTCREATESERVER";
1284 case DPERR_PLAYERLOST:
1285 return "DPERR_PLAYERLOST";
1286 case DPERR_SESSIONLOST:
1287 return "DPERR_SESSIONLOST";
1288 case DPERR_UNINITIALIZED:
1289 return "DPERR_UNINITIALIZED";
1290 case DPERR_NONEWPLAYERS:
1291 return "DPERR_NONEWPLAYERS";
1292 case DPERR_INVALIDPASSWORD:
1293 return "DPERR_INVALIDPASSWORD";
1294 case DPERR_CONNECTING:
1295 return "DPERR_CONNECTING";
1296 case DPERR_CONNECTIONLOST:
1297 return "DPERR_CONNECTIONLOST";
1298 case DPERR_UNKNOWNMESSAGE:
1299 return "DPERR_UNKNOWNMESSAGE";
1300 case DPERR_CANCELFAILED:
1301 return "DPERR_CANCELFAILED";
1302 case DPERR_INVALIDPRIORITY:
1303 return "DPERR_INVALIDPRIORITY";
1304 case DPERR_NOTHANDLED:
1305 return "DPERR_NOTHANDLED";
1306 case DPERR_CANCELLED:
1307 return "DPERR_CANCELLED";
1308 case DPERR_ABORTED:
1309 return "DPERR_ABORTED";
1310 case DPERR_BUFFERTOOLARGE:
1311 return "DPERR_BUFFERTOOLARGE";
1312 case DPERR_CANTCREATEPROCESS:
1313 return "DPERR_CANTCREATEPROCESS";
1314 case DPERR_APPNOTSTARTED:
1315 return "DPERR_APPNOTSTARTED";
1316 case DPERR_INVALIDINTERFACE:
1317 return "DPERR_INVALIDINTERFACE";
1318 case DPERR_NOSERVICEPROVIDER:
1319 return "DPERR_NOSERVICEPROVIDER";
1320 case DPERR_UNKNOWNAPPLICATION:
1321 return "DPERR_UNKNOWNAPPLICATION";
1322 case DPERR_NOTLOBBIED:
1323 return "DPERR_NOTLOBBIED";
1324 case DPERR_SERVICEPROVIDERLOADED:
1325 return "DPERR_SERVICEPROVIDERLOADED";
1326 case DPERR_ALREADYREGISTERED:
1327 return "DPERR_ALREADYREGISTERED";
1328 case DPERR_NOTREGISTERED:
1329 return "DPERR_NOTREGISTERED";
1330 case DPERR_AUTHENTICATIONFAILED:
1331 return "DPERR_AUTHENTICATIONFAILED";
1332 case DPERR_CANTLOADSSPI:
1333 return "DPERR_CANTLOADSSPI";
1334 case DPERR_ENCRYPTIONFAILED:
1335 return "DPERR_ENCRYPTIONFAILED";
1336 case DPERR_SIGNFAILED:
1337 return "DPERR_SIGNFAILED";
1338 case DPERR_CANTLOADSECURITYPACKAGE:
1339 return "DPERR_CANTLOADSECURITYPACKAGE";
1340 case DPERR_ENCRYPTIONNOTSUPPORTED:
1341 return "DPERR_ENCRYPTIONNOTSUPPORTED";
1342 case DPERR_CANTLOADCAPI:
1343 return "DPERR_CANTLOADCAPI";
1344 case DPERR_NOTLOGGEDIN:
1345 return "DPERR_NOTLOGGEDIN";
1346 case DPERR_LOGONDENIED:
1347 return "DPERR_LOGONDENIED";
1348 default:
1349 /* For errors not in the list, return HRESULT as a string
1350 This part is not thread safe */
1351 WARN( "Unknown error 0x%08x\n", hr );
1352 wsprintfA( szTempStr, "0x%08lx", hr );
1353 return szTempStr;