📄 dplayx_global.c
字号:
/* dplayx.dll global data implementation.
*
* Copyright 1999,2000 - Peter Hunnisett
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* NOTES:
* o Implementation of all things which are associated with dplay on
* the computer - ie shared resources and such. Methods in this
* compilation unit should not call anything out side this unit
* excepting base windows services and an interface to start the
* messaging thread.
* o Methods that begin with DPLAYX_ are used for dealing with
* dplayx.dll data which is accessible from all processes.
*
*/
#include <stdarg.h>
#include <string.h>
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "wine/debug.h"
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/unicode.h"
#include "wingdi.h"
#include "winuser.h"
#include "dplayx_global.h"
#include "dplayx_messages.h" /* For CreateMessageReceptionThread only */
WINE_DEFAULT_DEBUG_CHANNEL(dplay);
/* FIXME: Need to do all that fun other dll referencing type of stuff */
/* Static data for all processes */
static LPCSTR lpszDplayxSemaName = "WINE_DPLAYX_SM";
static HANDLE hDplayxSema;
static LPCSTR lpszDplayxFileMapping = "WINE_DPLAYX_FM";
static HANDLE hDplayxSharedMem;
static LPVOID lpSharedStaticData = NULL;
#define DPLAYX_AquireSemaphore() TRACE( "Waiting for DPLAYX semaphore\n" ); \
WaitForSingleObject( hDplayxSema, INFINITE );\
TRACE( "Through wait\n" )
#define DPLAYX_ReleaseSemaphore() ReleaseSemaphore( hDplayxSema, 1, NULL ); \
TRACE( "DPLAYX Semaphore released\n" ) /* FIXME: Is this correct? */
/* HACK for simple global data right now */
#define dwStaticSharedSize (128 * 1024) /* 128 KBytes */
#define dwDynamicSharedSize (512 * 1024) /* 512 KBytes */
#define dwTotalSharedSize ( dwStaticSharedSize + dwDynamicSharedSize )
/* FIXME: Is there no easier way? */
/* Pretend the entire dynamic area is carved up into 512 byte blocks.
* Each block has 4 bytes which are 0 unless used */
#define dwBlockSize 512
#define dwMaxBlock (dwDynamicSharedSize/dwBlockSize)
typedef struct
{
DWORD used;
DWORD data[dwBlockSize-sizeof(DWORD)];
} DPLAYX_MEM_SLICE;
static DPLAYX_MEM_SLICE* lpMemArea;
void DPLAYX_PrivHeapFree( LPVOID addr );
void DPLAYX_PrivHeapFree( LPVOID addr )
{
LPVOID lpAddrStart;
DWORD dwBlockUsed;
/* Handle getting passed a NULL */
if( addr == NULL )
{
return;
}
lpAddrStart = (char*)addr - sizeof(DWORD); /* Find block header */
dwBlockUsed = ((BYTE*)lpAddrStart - (BYTE*)lpMemArea)/dwBlockSize;
lpMemArea[ dwBlockUsed ].used = 0;
}
/* FIXME: This should be static, but is being used for a hack right now */
LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size );
LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size )
{
LPVOID lpvArea = NULL;
UINT uBlockUsed;
if( size > (dwBlockSize - sizeof(DWORD)) )
{
FIXME( "Size exceeded. Request of 0x%08lx\n", size );
size = dwBlockSize - sizeof(DWORD);
}
/* Find blank area */
uBlockUsed = 0;
while( ( lpMemArea[ uBlockUsed ].used != 0 ) && ( uBlockUsed <= dwMaxBlock ) ) { uBlockUsed++; }
if( uBlockUsed <= dwMaxBlock )
{
/* Set the area used */
lpMemArea[ uBlockUsed ].used = 1;
lpvArea = &(lpMemArea[ uBlockUsed ].data);
}
else
{
ERR( "No free block found\n" );
return NULL;
}
if( flags & HEAP_ZERO_MEMORY )
{
ZeroMemory( lpvArea, size );
}
return lpvArea;
}
LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str );
LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str )
{
LPSTR p = DPLAYX_PrivHeapAlloc( flags, strlen(str) + 1 );
if(p) {
strcpy( p, str );
}
return p;
}
LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str );
LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str )
{
INT len = strlenW(str) + 1;
LPWSTR p = DPLAYX_PrivHeapAlloc( flags, len * sizeof(WCHAR) );
if(p) {
strcpyW( p, str );
}
return p;
}
enum { numSupportedLobbies = 32, numSupportedSessions = 32 };
typedef struct tagDPLAYX_LOBBYDATA
{
/* Points to lpConn + block of contiguous extra memory for dynamic parts
* of the struct directly following
*/
LPDPLCONNECTION lpConn;
/* Information for dplobby interfaces */
DWORD dwAppID;
DWORD dwAppLaunchedFromID;
/* Should this lobby app send messages to creator at important life
* stages
*/
HANDLE hInformOnAppStart;
HANDLE hInformOnAppDeath;
HANDLE hInformOnSettingRead;
/* Sundries */
BOOL bWaitForConnectionSettings;
DWORD dwLobbyMsgThreadId;
} DPLAYX_LOBBYDATA, *LPDPLAYX_LOBBYDATA;
static DPLAYX_LOBBYDATA* lobbyData = NULL;
/* static DPLAYX_LOBBYDATA lobbyData[ numSupportedLobbies ]; */
static DPSESSIONDESC2* sessionData = NULL;
/* static DPSESSIONDESC2* sessionData[ numSupportedSessions ]; */
/* Function prototypes */
DWORD DPLAYX_SizeOfLobbyDataA( LPDPLCONNECTION lpDplData );
DWORD DPLAYX_SizeOfLobbyDataW( LPDPLCONNECTION lpDplData );
void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src );
void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src );
BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppId, LPDPLAYX_LOBBYDATA* dplData );
void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData );
BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2 lpSessionDest,
LPCDPSESSIONDESC2 lpSessionSrc );
/***************************************************************************
* Called to initialize the global data. This will only be used on the
* loading of the dll
***************************************************************************/
BOOL DPLAYX_ConstructData(void)
{
SECURITY_ATTRIBUTES s_attrib;
BOOL bInitializeSharedMemory = FALSE;
LPVOID lpDesiredMemoryMapStart = (LPVOID)0x50000000;
HANDLE hInformOnStart;
TRACE( "DPLAYX dll loaded - construct called\n" );
/* Create a semaphore to block access to DPLAYX global data structs */
s_attrib.bInheritHandle = TRUE;
s_attrib.lpSecurityDescriptor = NULL;
s_attrib.nLength = sizeof(s_attrib);
hDplayxSema = CreateSemaphoreA( &s_attrib, 1, 1, lpszDplayxSemaName );
/* First instance creates the semaphore. Others just use it */
if( GetLastError() == ERROR_SUCCESS )
{
TRACE( "Semaphore %p created\n", hDplayxSema );
/* The semaphore creator will also build the shared memory */
bInitializeSharedMemory = TRUE;
}
else if ( GetLastError() == ERROR_ALREADY_EXISTS )
{
TRACE( "Found semaphore handle %p\n", hDplayxSema );
}
else
{
ERR( ": semaphore error %ld\n", GetLastError() );
return FALSE;
}
SetLastError( ERROR_SUCCESS );
DPLAYX_AquireSemaphore();
hDplayxSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE,
&s_attrib,
PAGE_READWRITE | SEC_COMMIT,
0,
dwTotalSharedSize,
lpszDplayxFileMapping );
if( GetLastError() == ERROR_SUCCESS )
{
TRACE( "File mapped %p created\n", hDplayxSharedMem );
}
else if ( GetLastError() == ERROR_ALREADY_EXISTS )
{
TRACE( "Found FileMapping handle %p\n", hDplayxSharedMem );
}
else
{
ERR( ": unable to create shared memory (%ld)\n", GetLastError() );
return FALSE;
}
lpSharedStaticData = MapViewOfFileEx( hDplayxSharedMem,
FILE_MAP_WRITE,
0, 0, 0, lpDesiredMemoryMapStart );
if( lpSharedStaticData == NULL )
{
ERR( ": unable to map static data into process memory space (%ld)\n",
GetLastError() );
return FALSE;
}
else
{
if( lpDesiredMemoryMapStart == lpSharedStaticData )
{
TRACE( "File mapped to %p\n", lpSharedStaticData );
}
else
{
/* Presently the shared data structures use pointers. If the
* files are no mapped into the same area, the pointers will no
* longer make any sense :(
* FIXME: In the future make the shared data structures have some
* sort of fixup to make them independent between data spaces.
* This will also require a rework of the session data stuff.
*/
ERR( "File mapped to %p (not %p). Expect failure\n",
lpSharedStaticData, lpDesiredMemoryMapStart );
}
}
/* Dynamic area starts just after the static area */
lpMemArea = (LPVOID)((BYTE*)lpSharedStaticData + dwStaticSharedSize);
/* FIXME: Crude hack */
lobbyData = (DPLAYX_LOBBYDATA*)lpSharedStaticData;
sessionData = (DPSESSIONDESC2*)((BYTE*)lpSharedStaticData + (dwStaticSharedSize/2));
/* Initialize shared data segments. */
if( bInitializeSharedMemory )
{
UINT i;
TRACE( "Initializing shared memory\n" );
/* Set all lobbies to be "empty" */
for( i=0; i < numSupportedLobbies; i++ )
{
DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
}
/* Set all sessions to be "empty" */
for( i=0; i < numSupportedSessions; i++ )
{
sessionData[i].dwSize = 0;
}
/* Zero out the dynmaic area */
ZeroMemory( lpMemArea, dwDynamicSharedSize );
/* Just for fun sync the whole data area */
FlushViewOfFile( lpSharedStaticData, dwTotalSharedSize );
}
DPLAYX_ReleaseSemaphore();
/* Everything was created correctly. Signal the lobby client that
* we started up correctly
*/
if( DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, FALSE ) &&
hInformOnStart
)
{
BOOL bSuccess;
bSuccess = SetEvent( hInformOnStart );
TRACE( "Signalling lobby app start event %p %s\n",
hInformOnStart, bSuccess ? "succeed" : "failed" );
/* Close out handle */
DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, TRUE );
}
return TRUE;
}
/***************************************************************************
* Called to destroy all global data. This will only be used on the
* unloading of the dll
***************************************************************************/
BOOL DPLAYX_DestructData(void)
{
HANDLE hInformOnDeath;
TRACE( "DPLAYX dll unloaded - destruct called\n" );
/* If required, inform that this app is dying */
if( DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, FALSE ) &&
hInformOnDeath
)
{
BOOL bSuccess;
bSuccess = SetEvent( hInformOnDeath );
TRACE( "Signalling lobby app death event %p %s\n",
hInformOnDeath, bSuccess ? "succeed" : "failed" );
/* Close out handle */
DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, TRUE );
}
/* DO CLEAN UP (LAST) */
/* Delete the semaphore */
CloseHandle( hDplayxSema );
/* Delete shared memory file mapping */
UnmapViewOfFile( lpSharedStaticData );
CloseHandle( hDplayxSharedMem );
return FALSE;
}
void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData )
{
ZeroMemory( lpData, sizeof( *lpData ) );
}
/* NOTE: This must be called with the semaphore aquired.
* TRUE/FALSE with a pointer to it's data returned. Pointer data is
* is only valid if TRUE is returned.
*/
BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppID, LPDPLAYX_LOBBYDATA* lplpDplData )
{
UINT i;
*lplpDplData = NULL;
if( dwAppID == 0 )
{
dwAppID = GetCurrentProcessId();
TRACE( "Translated dwAppID == 0 into 0x%08lx\n", dwAppID );
}
for( i=0; i < numSupportedLobbies; i++ )
{
if( lobbyData[ i ].dwAppID == dwAppID )
{
/* This process is lobbied */
TRACE( "Found 0x%08lx @ %u\n", dwAppID, i );
*lplpDplData = &lobbyData[ i ];
return TRUE;
}
}
return FALSE;
}
/* Reserve a spot for the new appliction. TRUE means success and FALSE failure. */
BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID )
{
UINT i;
/* 0 is the marker for unused application data slots */
if( dwAppID == 0 )
{
return FALSE;
}
DPLAYX_AquireSemaphore();
/* Find an empty space in the list and insert the data */
for( i=0; i < numSupportedLobbies; i++ )
{
if( lobbyData[ i ].dwAppID == 0 )
{
/* This process is now lobbied */
TRACE( "Setting lobbyData[%u] for (0x%08lx,0x%08lx)\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -