📄 dplaysp.c
字号:
/* This contains the implementation of the interface Service
* Providers require to communicate with Direct Play
*
* Copyright 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
*/
#include <string.h>
#include "winerror.h"
#include "wine/debug.h"
#include "dpinit.h"
#include "dplaysp.h"
#include "dplay_global.h"
#include "name_server.h"
#include "dplayx_messages.h"
#include "dplayx_global.h" /* FIXME: For global hack */
/* FIXME: Need to add interface locking inside procedures */
WINE_DEFAULT_DEBUG_CHANNEL(dplay);
/* Prototypes */
static BOOL DPSP_CreateIUnknown( LPVOID lpSP );
static BOOL DPSP_DestroyIUnknown( LPVOID lpSP );
static BOOL DPSP_CreateDirectPlaySP( LPVOID lpSP, IDirectPlay2Impl* dp );
static BOOL DPSP_DestroyDirectPlaySP( LPVOID lpSP );
/* Predefine the interface */
typedef struct IDirectPlaySPImpl IDirectPlaySPImpl;
typedef struct tagDirectPlaySPIUnknownData
{
LONG ulObjRef;
CRITICAL_SECTION DPSP_lock;
} DirectPlaySPIUnknownData;
typedef struct tagDirectPlaySPData
{
LPVOID lpSpRemoteData;
DWORD dwSpRemoteDataSize; /* Size of data pointed to by lpSpRemoteData */
LPVOID lpSpLocalData;
DWORD dwSpLocalDataSize; /* Size of data pointed to by lpSpLocalData */
IDirectPlay2Impl* dplay; /* FIXME: This should perhaps be iface not impl */
} DirectPlaySPData;
#define DPSP_IMPL_FIELDS \
LONG ulInterfaceRef; \
DirectPlaySPIUnknownData* unk; \
DirectPlaySPData* sp;
struct IDirectPlaySPImpl
{
const IDirectPlaySPVtbl *lpVtbl;
DPSP_IMPL_FIELDS
};
/* Forward declaration of virtual tables */
static const IDirectPlaySPVtbl directPlaySPVT;
/* This structure is passed to the DP object for safe keeping */
typedef struct tagDP_SPPLAYERDATA
{
LPVOID lpPlayerLocalData;
DWORD dwPlayerLocalDataSize;
LPVOID lpPlayerRemoteData;
DWORD dwPlayerRemoteDataSize;
} DP_SPPLAYERDATA, *LPDP_SPPLAYERDATA;
/* Create the SP interface */
extern
HRESULT DPSP_CreateInterface( REFIID riid, LPVOID* ppvObj, IDirectPlay2Impl* dp )
{
TRACE( " for %s\n", debugstr_guid( riid ) );
*ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( IDirectPlaySPImpl ) );
if( *ppvObj == NULL )
{
return DPERR_OUTOFMEMORY;
}
if( IsEqualGUID( &IID_IDirectPlaySP, riid ) )
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)*ppvObj;
This->lpVtbl = &directPlaySPVT;
}
else
{
/* Unsupported interface */
HeapFree( GetProcessHeap(), 0, *ppvObj );
*ppvObj = NULL;
return E_NOINTERFACE;
}
/* Initialize it */
if( DPSP_CreateIUnknown( *ppvObj ) &&
DPSP_CreateDirectPlaySP( *ppvObj, dp )
)
{
IDirectPlaySP_AddRef( (LPDIRECTPLAYSP)*ppvObj );
return S_OK;
}
/* Initialize failed, destroy it */
DPSP_DestroyDirectPlaySP( *ppvObj );
DPSP_DestroyIUnknown( *ppvObj );
HeapFree( GetProcessHeap(), 0, *ppvObj );
*ppvObj = NULL;
return DPERR_NOMEMORY;
}
static BOOL DPSP_CreateIUnknown( LPVOID lpSP )
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)lpSP;
This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
if ( This->unk == NULL )
{
return FALSE;
}
InitializeCriticalSection( &This->unk->DPSP_lock );
return TRUE;
}
static BOOL DPSP_DestroyIUnknown( LPVOID lpSP )
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)lpSP;
DeleteCriticalSection( &This->unk->DPSP_lock );
HeapFree( GetProcessHeap(), 0, This->unk );
return TRUE;
}
static BOOL DPSP_CreateDirectPlaySP( LPVOID lpSP, IDirectPlay2Impl* dp )
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)lpSP;
This->sp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->sp) ) );
if ( This->sp == NULL )
{
return FALSE;
}
This->sp->dplay = dp;
/* Normally we should be keeping a reference, but since only the dplay
* interface that created us can destroy us, we do not keep a reference
* to it (ie we'd be stuck with always having one reference to the dplay
* object, and hence us, around).
* NOTE: The dp object does reference count us.
*
* FIXME: This is a kludge to get around a problem where a queryinterface
* is used to get a new interface and then is closed. We will then
* reference garbage. However, with this we will never deallocate
* the interface we store. The correct fix is to require all
* DP internal interfaces to use the This->dp2 interface which
* should be changed to This->dp
*/
IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp );
return TRUE;
}
static BOOL DPSP_DestroyDirectPlaySP( LPVOID lpSP )
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)lpSP;
/* Normally we should be keeping a reference, but since only the dplay
* interface that created us can destroy us, we do not keep a reference
* to it (ie we'd be stuck with always having one reference to the dplay
* object, and hence us, around).
* NOTE: The dp object does reference count us.
*/
/*IDirectPlayX_Release( (LPDIRECTPLAY2)This->sp->dplay ); */
HeapFree( GetProcessHeap(), 0, This->sp->lpSpRemoteData );
HeapFree( GetProcessHeap(), 0, This->sp->lpSpLocalData );
/* FIXME: Need to delete player queue */
HeapFree( GetProcessHeap(), 0, This->sp );
return TRUE;
}
/* Interface implementation */
static HRESULT WINAPI DPSP_QueryInterface
( LPDIRECTPLAYSP iface,
REFIID riid,
LPVOID* ppvObj )
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
*ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( *This ) );
if( *ppvObj == NULL )
{
return DPERR_OUTOFMEMORY;
}
CopyMemory( *ppvObj, This, sizeof( *This ) );
(*(IDirectPlaySPImpl**)ppvObj)->ulInterfaceRef = 0;
if( IsEqualGUID( &IID_IDirectPlaySP, riid ) )
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)*ppvObj;
This->lpVtbl = &directPlaySPVT;
}
else
{
/* Unsupported interface */
HeapFree( GetProcessHeap(), 0, *ppvObj );
*ppvObj = NULL;
return E_NOINTERFACE;
}
IDirectPlaySP_AddRef( (LPDIRECTPLAYSP)*ppvObj );
return S_OK;
}
static ULONG WINAPI DPSP_AddRef
( LPDIRECTPLAYSP iface )
{
ULONG ulInterfaceRefCount, ulObjRefCount;
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
TRACE( "ref count incremented to %lu:%lu for %p\n",
ulInterfaceRefCount, ulObjRefCount, This );
return ulObjRefCount;
}
static ULONG WINAPI DPSP_Release
( LPDIRECTPLAYSP iface )
{
ULONG ulInterfaceRefCount, ulObjRefCount;
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
TRACE( "ref count decremented to %lu:%lu for %p\n",
ulInterfaceRefCount, ulObjRefCount, This );
/* Deallocate if this is the last reference to the object */
if( ulObjRefCount == 0 )
{
DPSP_DestroyDirectPlaySP( This );
DPSP_DestroyIUnknown( This );
}
if( ulInterfaceRefCount == 0 )
{
HeapFree( GetProcessHeap(), 0, This );
}
return ulInterfaceRefCount;
}
static HRESULT WINAPI IDirectPlaySPImpl_AddMRUEntry
( LPDIRECTPLAYSP iface,
LPCWSTR lpSection,
LPCWSTR lpKey,
LPCVOID lpData,
DWORD dwDataSize,
DWORD dwMaxEntries
)
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
/* Should be able to call the comctl32 undocumented MRU routines.
I suspect that the interface works appropriately */
FIXME( "(%p)->(%p,%p%p,0x%08lx,0x%08lx): stub\n",
This, lpSection, lpKey, lpData, dwDataSize, dwMaxEntries );
return DP_OK;
}
static HRESULT WINAPI IDirectPlaySPImpl_CreateAddress
( LPDIRECTPLAYSP iface,
REFGUID guidSP,
REFGUID guidDataType,
LPCVOID lpData,
DWORD dwDataSize,
LPVOID lpAddress,
LPDWORD lpdwAddressSize
)
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
FIXME( "(%p)->(%s,%s,%p,0x%08lx,%p,%p): stub\n",
This, debugstr_guid(guidSP), debugstr_guid(guidDataType),
lpData, dwDataSize, lpAddress, lpdwAddressSize );
return DP_OK;
}
static HRESULT WINAPI IDirectPlaySPImpl_EnumAddress
( LPDIRECTPLAYSP iface,
LPDPENUMADDRESSCALLBACK lpEnumAddressCallback,
LPCVOID lpAddress,
DWORD dwAddressSize,
LPVOID lpContext
)
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
TRACE( "(%p)->(%p,%p,0x%08lx,%p)\n",
This, lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext );
DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext );
return DP_OK;
}
static HRESULT WINAPI IDirectPlaySPImpl_EnumMRUEntries
( LPDIRECTPLAYSP iface,
LPCWSTR lpSection,
LPCWSTR lpKey,
LPENUMMRUCALLBACK lpEnumMRUCallback,
LPVOID lpContext
)
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
/* Should be able to call the comctl32 undocumented MRU routines.
I suspect that the interface works appropriately */
FIXME( "(%p)->(%p,%p,%p,%p,): stub\n",
This, lpSection, lpKey, lpEnumMRUCallback, lpContext );
return DP_OK;
}
static HRESULT WINAPI IDirectPlaySPImpl_GetPlayerFlags
( LPDIRECTPLAYSP iface,
DPID idPlayer,
LPDWORD lpdwPlayerFlags
)
{
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
FIXME( "(%p)->(0x%08lx,%p): stub\n",
This, idPlayer, lpdwPlayerFlags );
return DP_OK;
}
static HRESULT WINAPI IDirectPlaySPImpl_GetSPPlayerData
( LPDIRECTPLAYSP iface,
DPID idPlayer,
LPVOID* lplpData,
LPDWORD lpdwDataSize,
DWORD dwFlags
)
{
HRESULT hr;
LPDP_SPPLAYERDATA lpPlayerData;
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx)\n",
This, idPlayer, lplpData, lpdwDataSize, dwFlags );
hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerData );
if( FAILED(hr) )
{
TRACE( "Couldn't get player data: %s\n", DPLAYX_HresultToString(hr) );
return DPERR_INVALIDPLAYER;
}
/* What to do in the case where there is nothing set yet? */
if( dwFlags == DPSET_LOCAL )
{
HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerLocalData );
*lplpData = lpPlayerData->lpPlayerLocalData;
*lpdwDataSize = lpPlayerData->dwPlayerLocalDataSize;
}
else if( dwFlags == DPSET_REMOTE )
{
HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerRemoteData );
*lplpData = lpPlayerData->lpPlayerRemoteData;
*lpdwDataSize = lpPlayerData->dwPlayerRemoteDataSize;
}
if( *lplpData == NULL )
{
hr = DPERR_GENERIC;
}
return hr;
}
static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
( LPDIRECTPLAYSP iface,
LPVOID lpMessageBody,
DWORD dwMessageBodySize,
LPVOID lpMessageHeader
)
{
LPDPMSG_SENDENVELOPE lpMsg = (LPDPMSG_SENDENVELOPE)lpMessageBody;
HRESULT hr = DPERR_GENERIC;
WORD wCommandId;
WORD wVersion;
DPSP_REPLYDATA data;
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n",
This, lpMessageBody, dwMessageBodySize, lpMessageHeader );
wCommandId = lpMsg->wCommandId;
wVersion = lpMsg->wVersion;
TRACE( "Incoming message has envelope of 0x%08lx, %u, %u\n",
lpMsg->dwMagic, wCommandId, wVersion );
if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG )
{
ERR( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic );
return DPERR_GENERIC;
}
#if 0
{
const LPDWORD lpcHeader = (LPDWORD)lpMessageHeader;
TRACE( "lpMessageHeader = [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx]\n",
lpcHeader[0], lpcHeader[1], lpcHeader[2], lpcHeader[3], lpcHeader[4] );
}
#endif
/* Pass everything else to Direct Play */
data.lpMessage = NULL;
data.dwMessageSize = 0;
/* Pass this message to the dplay interface to handle */
hr = DP_HandleMessage( This->sp->dplay, lpMessageBody, dwMessageBodySize,
lpMessageHeader, wCommandId, wVersion,
&data.lpMessage, &data.dwMessageSize );
if( FAILED(hr) )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -