977 lines
25 KiB
C
977 lines
25 KiB
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
|
|
{
|
|
ULONG 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 \
|
|
ULONG ulInterfaceRef; \
|
|
DirectPlaySPIUnknownData* unk; \
|
|
DirectPlaySPData* sp;
|
|
|
|
struct IDirectPlaySPImpl
|
|
{
|
|
IDirectPlaySPVtbl *lpVtbl;
|
|
DPSP_IMPL_FIELDS
|
|
};
|
|
|
|
/* Forward declaration of virtual tables */
|
|
static 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 = (DirectPlaySPIUnknownData*)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 = (DirectPlaySPData*)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 )
|
|
{
|
|
if( lpPlayerData->lpPlayerLocalData )
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerLocalData );
|
|
}
|
|
|
|
*lplpData = lpPlayerData->lpPlayerLocalData;
|
|
*lpdwDataSize = lpPlayerData->dwPlayerLocalDataSize;
|
|
}
|
|
else if( dwFlags == DPSET_REMOTE )
|
|
{
|
|
if( lpPlayerData->lpPlayerRemoteData )
|
|
{
|
|
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) )
|
|
{
|
|
ERR( "Command processing failed %s\n", DPLAYX_HresultToString(hr) );
|
|
}
|
|
|
|
/* Do we want a reply? */
|
|
if( data.lpMessage != NULL )
|
|
{
|
|
data.lpSPMessageHeader = lpMessageHeader;
|
|
data.idNameServer = 0;
|
|
data.lpISP = iface;
|
|
|
|
hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data );
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr) );
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
|
|
#if 0
|
|
HRESULT hr = DP_OK;
|
|
HANDLE hReceiveEvent = 0;
|
|
/* FIXME: Aquire some sort of interface lock */
|
|
/* FIXME: Need some sort of context for this callback. Need to determine
|
|
* how this is actually done with the SP
|
|
*/
|
|
/* FIXME: Who needs to delete the message when done? */
|
|
switch( lpMsg->dwType )
|
|
{
|
|
case DPSYS_CREATEPLAYERORGROUP:
|
|
{
|
|
LPDPMSG_CREATEPLAYERORGROUP msg = (LPDPMSG_CREATEPLAYERORGROUP)lpMsg;
|
|
|
|
if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
|
|
{
|
|
hr = DP_IF_CreatePlayer( This, lpMessageHeader, msg->dpId,
|
|
&msg->dpnName, 0, msg->lpData,
|
|
msg->dwDataSize, msg->dwFlags, ... );
|
|
}
|
|
else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
|
|
{
|
|
/* Group in group situation? */
|
|
if( msg->dpIdParent == DPID_NOPARENT_GROUP )
|
|
{
|
|
hr = DP_IF_CreateGroup( This, lpMessageHeader, msg->dpId,
|
|
&msg->dpnName, 0, msg->lpData,
|
|
msg->dwDataSize, msg->dwFlags, ... );
|
|
}
|
|
else /* Group in Group */
|
|
{
|
|
hr = DP_IF_CreateGroupInGroup( This, lpMessageHeader, msg->dpIdParent,
|
|
&msg->dpnName, 0, msg->lpData,
|
|
msg->dwDataSize, msg->dwFlags, ... );
|
|
}
|
|
}
|
|
else /* Hmmm? */
|
|
{
|
|
ERR( "Corrupt msg->dwPlayerType for DPSYS_CREATEPLAYERORGROUP\n" );
|
|
return;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_DESTROYPLAYERORGROUP:
|
|
{
|
|
LPDPMSG_DESTROYPLAYERORGROUP msg = (LPDPMSG_DESTROYPLAYERORGROUP)lpMsg;
|
|
|
|
if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
|
|
{
|
|
hr = DP_IF_DestroyPlayer( This, msg->dpId, ... );
|
|
}
|
|
else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
|
|
{
|
|
hr = DP_IF_DestroyGroup( This, msg->dpId, ... );
|
|
}
|
|
else /* Hmmm? */
|
|
{
|
|
ERR( "Corrupt msg->dwPlayerType for DPSYS_DESTROYPLAYERORGROUP\n" );
|
|
return;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_ADDPLAYERTOGROUP:
|
|
{
|
|
LPDPMSG_ADDPLAYERTOGROUP msg = (LPDPMSG_ADDPLAYERTOGROUP)lpMsg;
|
|
|
|
hr = DP_IF_AddPlayerToGroup( This, msg->dpIdGroup, msg->dpIdPlayer, ... );
|
|
break;
|
|
}
|
|
|
|
case DPSYS_DELETEPLAYERFROMGROUP:
|
|
{
|
|
LPDPMSG_DELETEPLAYERFROMGROUP msg = (LPDPMSG_DELETEPLAYERFROMGROUP)lpMsg;
|
|
|
|
hr = DP_IF_DeletePlayerFromGroup( This, msg->dpIdGroup, msg->dpIdPlayer,
|
|
... );
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_SESSIONLOST:
|
|
{
|
|
LPDPMSG_SESSIONLOST msg = (LPDPMSG_SESSIONLOST)lpMsg;
|
|
|
|
FIXME( "DPSYS_SESSIONLOST not handled\n" );
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_HOST:
|
|
{
|
|
LPDPMSG_HOST msg = (LPDPMSG_HOST)lpMsg;
|
|
|
|
FIXME( "DPSYS_HOST not handled\n" );
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_SETPLAYERORGROUPDATA:
|
|
{
|
|
LPDPMSG_SETPLAYERORGROUPDATA msg = (LPDPMSG_SETPLAYERORGROUPDATA)lpMsg;
|
|
|
|
if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
|
|
{
|
|
hr = DP_IF_SetPlayerData( This, msg->dpId, msg->lpData, msg->dwDataSize, DPSET_REMOTE, ... );
|
|
}
|
|
else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
|
|
{
|
|
hr = DP_IF_SetGroupData( This, msg->dpId, msg->lpData, msg->dwDataSize,
|
|
DPSET_REMOTE, ... );
|
|
}
|
|
else /* Hmmm? */
|
|
{
|
|
ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
|
|
return;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_SETPLAYERORGROUPNAME:
|
|
{
|
|
LPDPMSG_SETPLAYERORGROUPNAME msg = (LPDPMSG_SETPLAYERORGROUPNAME)lpMsg;
|
|
|
|
if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
|
|
{
|
|
hr = DP_IF_SetPlayerName( This, msg->dpId, msg->dpnName, ... );
|
|
}
|
|
else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
|
|
{
|
|
hr = DP_IF_SetGroupName( This, msg->dpId, msg->dpnName, ... );
|
|
}
|
|
else /* Hmmm? */
|
|
{
|
|
ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
|
|
return;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_SETSESSIONDESC;
|
|
{
|
|
LPDPMSG_SETSESSIONDESC msg = (LPDPMSG_SETSESSIONDESC)lpMsg;
|
|
|
|
hr = DP_IF_SetSessionDesc( This, &msg->dpDesc );
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_ADDGROUPTOGROUP:
|
|
{
|
|
LPDPMSG_ADDGROUPTOGROUP msg = (LPDPMSG_ADDGROUPTOGROUP)lpMsg;
|
|
|
|
hr = DP_IF_AddGroupToGroup( This, msg->dpIdParentGroup, msg->dpIdGroup,
|
|
... );
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_DELETEGROUPFROMGROUP:
|
|
{
|
|
LPDPMSG_DELETEGROUPFROMGROUP msg = (LPDPMSG_DELETEGROUPFROMGROUP)lpMsg;
|
|
|
|
hr = DP_IF_DeleteGroupFromGroup( This, msg->dpIdParentGroup,
|
|
msg->dpIdGroup, ... );
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_SECUREMESSAGE:
|
|
{
|
|
LPDPMSG_SECUREMESSAGE msg = (LPDPMSG_SECUREMESSAGE)lpMsg;
|
|
|
|
FIXME( "DPSYS_SECUREMESSAGE not implemented\n" );
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_STARTSESSION:
|
|
{
|
|
LPDPMSG_STARTSESSION msg = (LPDPMSG_STARTSESSION)lpMsg;
|
|
|
|
FIXME( "DPSYS_STARTSESSION not implemented\n" );
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_CHAT:
|
|
{
|
|
LPDPMSG_CHAT msg = (LPDPMSG_CHAT)lpMsg;
|
|
|
|
FIXME( "DPSYS_CHAT not implemeneted\n" );
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_SETGROUPOWNER:
|
|
{
|
|
LPDPMSG_SETGROUPOWNER msg = (LPDPMSG_SETGROUPOWNER)lpMsg;
|
|
|
|
FIXME( "DPSYS_SETGROUPOWNER not implemented\n" );
|
|
|
|
break;
|
|
}
|
|
|
|
case DPSYS_SENDCOMPLETE:
|
|
{
|
|
LPDPMSG_SENDCOMPLETE msg = (LPDPMSG_SENDCOMPLETE)lpMsg;
|
|
|
|
FIXME( "DPSYS_SENDCOMPLETE not implemented\n" );
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
/* NOTE: This should be a user defined type. There is nothing that we
|
|
* need to do with it except queue it.
|
|
*/
|
|
TRACE( "Received user message type(?) 0x%08lx through SP.\n",
|
|
lpMsg->dwType );
|
|
break;
|
|
}
|
|
}
|
|
|
|
FIXME( "Queue message in the receive queue. Need some context data!\n" );
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
ERR( "Unable to perform action for msg type 0x%08lx\n", lpMsg->dwType );
|
|
}
|
|
/* If a receive event was registered for this player, invoke it */
|
|
if( hReceiveEvent )
|
|
{
|
|
SetEvent( hReceiveEvent );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData
|
|
( LPDIRECTPLAYSP iface,
|
|
DPID idPlayer,
|
|
LPVOID lpData,
|
|
DWORD dwDataSize,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
LPDP_SPPLAYERDATA lpPlayerEntry;
|
|
LPVOID lpPlayerData;
|
|
|
|
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
|
|
|
|
/* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
|
|
TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx)\n",
|
|
This, idPlayer, lpData, dwDataSize, dwFlags );
|
|
|
|
hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerEntry );
|
|
if( FAILED(hr) )
|
|
{
|
|
/* Player must not exist */
|
|
return DPERR_INVALIDPLAYER;
|
|
}
|
|
|
|
lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
|
|
CopyMemory( lpPlayerData, lpData, dwDataSize );
|
|
|
|
if( dwFlags == DPSET_LOCAL )
|
|
{
|
|
lpPlayerEntry->lpPlayerLocalData = lpPlayerData;
|
|
lpPlayerEntry->dwPlayerLocalDataSize = dwDataSize;
|
|
}
|
|
else if( dwFlags == DPSET_REMOTE )
|
|
{
|
|
lpPlayerEntry->lpPlayerRemoteData = lpPlayerData;
|
|
lpPlayerEntry->dwPlayerRemoteDataSize = dwDataSize;
|
|
}
|
|
|
|
hr = DP_SetSPPlayerData( This->sp->dplay, idPlayer, lpPlayerEntry );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress
|
|
( LPDIRECTPLAYSP iface,
|
|
LPCDPCOMPOUNDADDRESSELEMENT lpElements,
|
|
DWORD dwElementCount,
|
|
LPVOID lpAddress,
|
|
LPDWORD lpdwAddressSize
|
|
)
|
|
{
|
|
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
|
|
|
|
FIXME( "(%p)->(%p,0x%08lx,%p,%p): stub\n",
|
|
This, lpElements, dwElementCount, lpAddress, lpdwAddressSize );
|
|
|
|
return DP_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IDirectPlaySPImpl_GetSPData
|
|
( LPDIRECTPLAYSP iface,
|
|
LPVOID* lplpData,
|
|
LPDWORD lpdwDataSize,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
HRESULT hr = DP_OK;
|
|
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
|
|
|
|
/* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
|
|
TRACE( "(%p)->(%p,%p,0x%08lx)\n",
|
|
This, lplpData, lpdwDataSize, dwFlags );
|
|
|
|
#if 0
|
|
/* This is what the documentation says... */
|
|
if( dwFlags != DPSET_REMOTE )
|
|
{
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
#else
|
|
/* ... but most service providers call this with 1 */
|
|
/* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
|
|
* thing?
|
|
*/
|
|
if( dwFlags != DPSET_REMOTE )
|
|
{
|
|
TRACE( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
|
|
}
|
|
#endif
|
|
|
|
/* FIXME: What to do in the case where this isn't initialized yet? */
|
|
|
|
/* Yes, we're supposed to return a pointer to the memory we have stored! */
|
|
if( dwFlags == DPSET_REMOTE )
|
|
{
|
|
*lpdwDataSize = This->sp->dwSpRemoteDataSize;
|
|
*lplpData = This->sp->lpSpRemoteData;
|
|
|
|
if( This->sp->lpSpRemoteData == NULL )
|
|
{
|
|
hr = DPERR_GENERIC;
|
|
}
|
|
}
|
|
else if( dwFlags == DPSET_LOCAL )
|
|
{
|
|
*lpdwDataSize = This->sp->dwSpLocalDataSize;
|
|
*lplpData = This->sp->lpSpLocalData;
|
|
|
|
if( This->sp->lpSpLocalData == NULL )
|
|
{
|
|
hr = DPERR_GENERIC;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI IDirectPlaySPImpl_SetSPData
|
|
( LPDIRECTPLAYSP iface,
|
|
LPVOID lpData,
|
|
DWORD dwDataSize,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
LPVOID lpSpData;
|
|
|
|
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
|
|
|
|
/* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
|
|
TRACE( "(%p)->(%p,0x%08lx,0x%08lx)\n",
|
|
This, lpData, dwDataSize, dwFlags );
|
|
|
|
#if 0
|
|
/* This is what the documentation says... */
|
|
if( dwFlags != DPSET_REMOTE )
|
|
{
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
#else
|
|
/* ... but most service providers call this with 1 */
|
|
/* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
|
|
* thing?
|
|
*/
|
|
if( dwFlags != DPSET_REMOTE )
|
|
{
|
|
TRACE( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
|
|
}
|
|
#endif
|
|
|
|
lpSpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
|
|
CopyMemory( lpSpData, lpData, dwDataSize );
|
|
|
|
/* If we have data already allocated, free it and replace it */
|
|
if( dwFlags == DPSET_REMOTE )
|
|
{
|
|
if( This->sp->lpSpRemoteData )
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, This->sp->lpSpRemoteData );
|
|
}
|
|
|
|
This->sp->dwSpRemoteDataSize = dwDataSize;
|
|
This->sp->lpSpRemoteData = lpSpData;
|
|
}
|
|
else if ( dwFlags == DPSET_LOCAL )
|
|
{
|
|
if( This->sp->lpSpLocalData )
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, This->sp->lpSpLocalData );
|
|
}
|
|
|
|
This->sp->lpSpLocalData = lpSpData;
|
|
This->sp->dwSpLocalDataSize = dwDataSize;
|
|
}
|
|
|
|
return DP_OK;
|
|
}
|
|
|
|
static VOID WINAPI IDirectPlaySPImpl_SendComplete
|
|
( LPDIRECTPLAYSP iface,
|
|
LPVOID unknownA,
|
|
DWORD unknownB
|
|
)
|
|
{
|
|
IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
|
|
|
|
FIXME( "(%p)->(%p,0x%08lx): stub\n",
|
|
This, unknownA, unknownB );
|
|
}
|
|
|
|
|
|
static struct IDirectPlaySPVtbl directPlaySPVT =
|
|
{
|
|
|
|
DPSP_QueryInterface,
|
|
DPSP_AddRef,
|
|
DPSP_Release,
|
|
|
|
IDirectPlaySPImpl_AddMRUEntry,
|
|
IDirectPlaySPImpl_CreateAddress,
|
|
IDirectPlaySPImpl_EnumAddress,
|
|
IDirectPlaySPImpl_EnumMRUEntries,
|
|
IDirectPlaySPImpl_GetPlayerFlags,
|
|
IDirectPlaySPImpl_GetSPPlayerData,
|
|
IDirectPlaySPImpl_HandleMessage,
|
|
IDirectPlaySPImpl_SetSPPlayerData,
|
|
IDirectPlaySPImpl_CreateCompoundAddress,
|
|
IDirectPlaySPImpl_GetSPData,
|
|
IDirectPlaySPImpl_SetSPData,
|
|
IDirectPlaySPImpl_SendComplete
|
|
};
|
|
|
|
|
|
/* DP external interfaces to call into DPSP interface */
|
|
|
|
/* Allocate the structure */
|
|
extern LPVOID DPSP_CreateSPPlayerData(void)
|
|
{
|
|
TRACE( "Creating SPPlayer data struct\n" );
|
|
return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
sizeof( DP_SPPLAYERDATA ) );
|
|
}
|