- Implemented loading and initialization of service providers

- Created service provider COM object
- Lots of dplay/dplobby implementation/fixes
- Clean up of ole/guid.c
This commit is contained in:
Peter Hunnisett 2000-08-25 21:58:05 +00:00 committed by Alexandre Julliard
parent 217a682b4f
commit ef6dca5c37
19 changed files with 4909 additions and 1671 deletions

View File

@ -9,6 +9,7 @@ IMPORTS = ole32 advapi32 kernel32
C_SRCS = \ C_SRCS = \
dpclassfactory.c \ dpclassfactory.c \
dplay.c \ dplay.c \
dplaysp.c \
dplayx_global.c \ dplayx_global.c \
dplayx_main.c \ dplayx_main.c \
dplayx_messages.c \ dplayx_messages.c \

View File

@ -39,7 +39,6 @@ static ULONG WINAPI DP_and_DPL_Release(LPCLASSFACTORY iface) {
return --(This->ref); return --(This->ref);
} }
/* Not the most efficient implementation, but it's simple */
static HRESULT WINAPI DP_and_DPL_CreateInstance( static HRESULT WINAPI DP_and_DPL_CreateInstance(
LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
) { ) {
@ -47,12 +46,11 @@ static HRESULT WINAPI DP_and_DPL_CreateInstance(
TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
/* FIXME: reuse already created DP/DPL object if present? */ if ( DPL_CreateInterface( riid, ppobj ) == S_OK )
if ( directPlayLobby_QueryInterface( riid, ppobj ) == S_OK )
{ {
return S_OK; return S_OK;
} }
else if ( directPlay_QueryInterface( riid, ppobj ) == S_OK ) else if ( DP_CreateInterface( riid, ppobj ) == S_OK )
{ {
return S_OK; return S_OK;
} }
@ -110,13 +108,3 @@ DWORD WINAPI DPLAYX_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
ERR("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); ERR("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
return CLASS_E_CLASSNOTAVAILABLE; return CLASS_E_CLASSNOTAVAILABLE;
} }
/***********************************************************************
* DllCanUnloadNow (DPLAYX.@)
*/
HRESULT WINAPI DPLAYX_DllCanUnloadNow(void)
{
FIXME("(void): stub\n");
return S_FALSE;
}

View File

@ -2,7 +2,12 @@
#ifndef __WINE_DPINIT_H #ifndef __WINE_DPINIT_H
#define __WINE_DPINIT_H #define __WINE_DPINIT_H
extern HRESULT directPlay_QueryInterface( REFIID riid, LPVOID* ppvObj ); #include "wtypes.h"
extern HRESULT directPlayLobby_QueryInterface( REFIID riid, LPVOID* ppvObj ); #include "dplay_global.h"
extern HRESULT DP_CreateInterface( REFIID riid, LPVOID* ppvObj );
extern HRESULT DPL_CreateInterface( REFIID riid, LPVOID* ppvObj );
extern HRESULT DPSP_CreateInterface( REFIID riid, LPVOID* ppvObj,
IDirectPlay2Impl* dp );
#endif #endif

File diff suppressed because it is too large Load Diff

185
dlls/dplayx/dplay_global.h Normal file
View File

@ -0,0 +1,185 @@
#ifndef __WINE_DPLAY_GLOBAL_INCLUDED
#define __WINE_DPLAY_GLOBAL_INCLUDED
#include "dplaysp.h"
#include "dplayx_queue.h"
extern HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback,
LPCVOID lpAddress, DWORD dwAddressSize,
LPVOID lpContext );
extern DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
/*****************************************************************************
* Predeclare the interface implementation structures
*/
typedef struct IDirectPlay2Impl IDirectPlay2AImpl;
typedef struct IDirectPlay2Impl IDirectPlay2Impl;
typedef struct IDirectPlay3Impl IDirectPlay3AImpl;
typedef struct IDirectPlay3Impl IDirectPlay3Impl;
typedef struct IDirectPlay4Impl IDirectPlay4AImpl;
typedef struct IDirectPlay4Impl IDirectPlay4Impl;
typedef struct tagDirectPlayIUnknownData
{
ULONG ulObjRef;
CRITICAL_SECTION DP_lock;
} DirectPlayIUnknownData;
typedef struct tagEnumSessionAsyncCallbackData
{
LPSPINITDATA lpSpData;
GUID requestGuid;
DWORD dwEnumSessionFlags;
DWORD dwTimeout;
HANDLE hSuicideRequest;
} EnumSessionAsyncCallbackData;
struct PlayerData
{
/* Individual player information */
DPID dpid;
DPNAME name;
HANDLE hEvent;
/* View of local data */
LPVOID lpLocalData;
DWORD dwLocalDataSize;
/* View of remote data */
LPVOID lpRemoteData;
DWORD dwRemoteDataSize;
DWORD dwFlags; /* Special remarks about the type of player */
};
typedef struct PlayerData* lpPlayerData;
struct PlayerList
{
DPQ_ENTRY(PlayerList) players;
lpPlayerData lpPData;
};
typedef struct PlayerList* lpPlayerList;
struct GroupData
{
/* Internal information */
DPID parent; /* If parent == 0 it's a top level group */
DPQ_HEAD(GroupList) groups; /* A group has [0..n] groups */
DPQ_HEAD(PlayerList) players; /* A group has [0..n] players */
DPID idGroupOwner; /* ID of player who owns the group */
DWORD dwFlags; /* Flags describing anything special about the group */
DPID dpid;
DPNAME name;
/* View of local data */
LPVOID lpLocalData;
DWORD dwLocalDataSize;
/* View of remote data */
LPVOID lpRemoteData;
DWORD dwRemoteDataSize;
};
typedef struct GroupData GroupData;
typedef struct GroupData* lpGroupData;
struct GroupList
{
DPQ_ENTRY(GroupList) groups;
lpGroupData lpGData;
};
typedef struct GroupList* lpGroupList;
struct DPMSG
{
DPQ_ENTRY( DPMSG ) msgs;
DPMSG_GENERIC* msg;
};
typedef struct DPMSG* LPDPMSG;
/* Contains all dp1 and dp2 data members */
typedef struct tagDirectPlay2Data
{
BOOL bConnectionOpen;
/* For async EnumSessions requests */
HANDLE hEnumSessionThread;
HANDLE hKillEnumSessionThreadEvent;
LPVOID lpNameServerData; /* DPlay interface doesn't know contents */
BOOL bHostInterface; /* Did this interface create the session */
#if 0
DPQ_HEAD(PlayerList) players; /* All players w/ interface */
DPQ_HEAD(GroupList) groups; /* All main groups w/ interface */
#else
lpGroupData lpSysGroup; /* System group with _everything_ in it */
#endif
LPDPSESSIONDESC2 lpSessionDesc;
/* I/O Msg queues */
DPQ_HEAD( DPMSG ) receiveMsgs; /* Msg receive queue */
DPQ_HEAD( DPMSG ) sendMsgs; /* Msg send pending queue */
/* Information about the service provider active on this connection */
SPINITDATA spData;
/* Our service provider */
HMODULE hServiceProvider;
BOOL bConnectionInitialized;
} DirectPlay2Data;
typedef struct tagDirectPlay3Data
{
BOOL dummy;
} DirectPlay3Data;
typedef struct tagDirectPlay4Data
{
BOOL dummy;
} DirectPlay4Data;
#define DP_IMPL_FIELDS \
ULONG ulInterfaceRef; \
DirectPlayIUnknownData* unk; \
DirectPlay2Data* dp2; \
DirectPlay3Data* dp3; \
DirectPlay4Data* dp4;
struct IDirectPlay2Impl
{
ICOM_VFIELD(IDirectPlay2);
DP_IMPL_FIELDS
};
struct IDirectPlay3Impl
{
ICOM_VFIELD(IDirectPlay3);
DP_IMPL_FIELDS
};
struct IDirectPlay4Impl
{
ICOM_VFIELD(IDirectPlay4);
DP_IMPL_FIELDS
};
/* Forward declarations of virtual tables */
extern ICOM_VTABLE(IDirectPlay2) directPlay2AVT;
extern ICOM_VTABLE(IDirectPlay3) directPlay3AVT;
extern ICOM_VTABLE(IDirectPlay4) directPlay4AVT;
extern ICOM_VTABLE(IDirectPlay2) directPlay2WVT;
extern ICOM_VTABLE(IDirectPlay3) directPlay3WVT;
extern ICOM_VTABLE(IDirectPlay4) directPlay4WVT;
#endif /* __WINE_DPLAY_GLOBAL_INCLUDED */

880
dlls/dplayx/dplaysp.c Normal file
View File

@ -0,0 +1,880 @@
/* This contains the implementation of the interface Service
* Providers require to communicate with Direct Play
*
* Copyright 2000 Peter Hunnisett <hunnise@nortelnetworks.com>
*/
#include "heap.h"
#include "winerror.h"
#include "debugtools.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 */
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 */
LPVOID lpPlayerData; /* FIXME: Need to figure out how this actually behaves */
DWORD dwPlayerDataSize;
} DirectPlaySPData;
#define DPSP_IMPL_FIELDS \
ULONG ulInterfaceRef; \
DirectPlaySPIUnknownData* unk; \
DirectPlaySPData* sp;
struct IDirectPlaySPImpl
{
ICOM_VFIELD(IDirectPlaySP);
DPSP_IMPL_FIELDS
};
/* Forward declaration of virtual tables */
static ICOM_VTABLE(IDirectPlaySP) directPlaySPVT;
/* 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 ) )
{
ICOM_THIS(IDirectPlaySPImpl,*ppvObj);
ICOM_VTBL(This) = &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 )
{
ICOM_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 )
{
ICOM_THIS(IDirectPlaySPImpl,lpSP);
DeleteCriticalSection( &This->unk->DPSP_lock );
HeapFree( GetProcessHeap(), 0, This->unk );
return TRUE;
}
static BOOL DPSP_CreateDirectPlaySP( LPVOID lpSP, IDirectPlay2Impl* dp )
{
ICOM_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.
*/
/* IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp ); */
return TRUE;
}
static BOOL DPSP_DestroyDirectPlaySP( LPVOID lpSP )
{
ICOM_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 )
{
ICOM_THIS(IDirectPlaySPImpl,iface);
TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
*ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( IDirectPlaySPImpl ) );
if( *ppvObj == NULL )
{
return DPERR_OUTOFMEMORY;
}
CopyMemory( *ppvObj, iface, sizeof( IDirectPlaySPImpl ) );
(*(IDirectPlaySPImpl**)ppvObj)->ulInterfaceRef = 0;
if( IsEqualGUID( &IID_IDirectPlaySP, riid ) )
{
ICOM_THIS(IDirectPlaySPImpl,*ppvObj);
ICOM_VTBL(This) = &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;
ICOM_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;
ICOM_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
)
{
ICOM_THIS(IDirectPlaySPImpl,iface);
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
)
{
ICOM_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
)
{
ICOM_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
)
{
ICOM_THIS(IDirectPlaySPImpl,iface);
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
)
{
ICOM_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
)
{
ICOM_THIS(IDirectPlaySPImpl,iface);
TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
FIXME( "(%p)->(0x%08lx,%p,%p,0x%08lx): stub\n",
This, idPlayer, lplpData, lpdwDataSize, dwFlags );
*lplpData = This->sp->lpPlayerData;
*lpdwDataSize = This->sp->dwPlayerDataSize;
return DP_OK;
}
static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
( LPDIRECTPLAYSP iface,
LPVOID lpMessageBody,
DWORD dwMessageBodySize,
LPVOID lpMessageHeader
)
{
LPDPMSG_SENDENVELOPE lpMsg = (LPDPMSG_SENDENVELOPE)lpMessageBody;
HRESULT hr = DPERR_GENERIC;
ICOM_THIS(IDirectPlaySPImpl,iface);
TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n",
This, lpMessageBody, dwMessageBodySize, lpMessageHeader );
TRACE( "Incomming message has envelope of 0x%08lx, %u, %u\n",
lpMsg->dwMagic, lpMsg->wCommandId, lpMsg->wVersion );
if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG )
{
FIXME( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic );
}
switch( lpMsg->wCommandId )
{
case DPMSGCMD_ENUMSESSIONSREQUEST:
{
DPSP_REPLYDATA data;
data.lpSPMessageHeader = lpMessageHeader;
data.idNameServer = 0;
data.lpISP = iface;
NS_ReplyToEnumSessionsRequest( lpMessageBody, &data, This->sp->dplay );
hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data );
if( FAILED(hr) )
{
ERR( "Reply failed 0x%08lx\n", hr );
}
break;
}
case DPMSGCMD_ENUMSESSIONSREPLY:
{
NS_SetRemoteComputerAsNameServer( lpMessageHeader,
This->sp->dplay->dp2->spData.dwSPHeaderSize,
(LPDPMSG_ENUMSESSIONSREPLY)lpMessageBody,
This->sp->dplay->dp2->lpNameServerData );
/* No reply expected */
break;
}
default:
FIXME( "Unknown Command of %u\n", lpMsg->wCommandId );
}
#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: Add in size checks for all messages to determine corrupt messages */ /* FIXME: Who needs to delete the message when done? */
/* FIXME: Does this get invoked as soon as the message arrives, or as soon
* as it's removed from the queue (or peeked in queue?)
*/
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 receieve event was registered for this player, invoke it */
if( hReceiveEvent )
{
SetEvent( hReceiveEvent );
}
#endif
return hr;
}
static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData
( LPDIRECTPLAYSP iface,
DPID idPlayer,
LPVOID lpData,
DWORD dwDataSize,
DWORD dwFlags
)
{
ICOM_THIS(IDirectPlaySPImpl,iface);
/* FIXME: I'm not sure if this stuff should be associated with the DPlay
* player lists. How else would this stuff get deleted?
*/
TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
FIXME( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx): stub\n",
This, idPlayer, lpData, dwDataSize, dwFlags );
This->sp->lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
This->sp->dwPlayerDataSize = dwDataSize;
CopyMemory( This->sp->lpPlayerData, lpData, dwDataSize );
return DP_OK;
}
static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress
( LPDIRECTPLAYSP iface,
LPCDPCOMPOUNDADDRESSELEMENT lpElements,
DWORD dwElementCount,
LPVOID lpAddress,
LPDWORD lpdwAddressSize
)
{
ICOM_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
)
{
ICOM_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 != 0 )
{
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 != 0 )
{
FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
}
#endif
/* 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;
}
else if( dwFlags == DPSET_LOCAL )
{
*lpdwDataSize = This->sp->dwSpLocalDataSize;
*lplpData = This->sp->lpSpLocalData;
}
return DP_OK;
}
static HRESULT WINAPI IDirectPlaySPImpl_SetSPData
( LPDIRECTPLAYSP iface,
LPVOID lpData,
DWORD dwDataSize,
DWORD dwFlags
)
{
LPVOID lpSpData;
ICOM_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 != 0 )
{
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 != 0 )
{
FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
}
#endif
if( dwFlags == DPSET_REMOTE )
{
lpSpData = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, dwDataSize );
}
else
{
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 )
{
/* FIXME: This doesn't strictly make sense as there is no means to share
* this shared data. Must be misinterpreting something...
*/
if( This->sp->lpSpRemoteData )
{
DPLAYX_PrivHeapFree( This->sp->lpSpRemoteData );
}
/* NOTE: dwDataSize is also stored in the heap structure */
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
)
{
ICOM_THIS(IDirectPlaySPImpl,iface);
FIXME( "(%p)->(%p,0x%08lx): stub\n",
This, unknownA, unknownB );
}
static struct ICOM_VTABLE(IDirectPlaySP) directPlaySPVT =
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
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
};

337
dlls/dplayx/dplaysp.h Normal file
View File

@ -0,0 +1,337 @@
#ifndef __WINE_DIRECT_PLAY_SP_H
#define __WINE_DIRECT_PLAY_SP_H
#include "dplay.h"
#include "dplobby.h"
/* GUID for IDirectPlaySP {0C9F6360-CC61-11cf-ACEC-00AA006886E3} */
DEFINE_GUID(IID_IDirectPlaySP, 0xc9f6360, 0xcc61, 0x11cf, 0xac, 0xec, 0x0, 0xaa, 0x0, 0x68, 0x86, 0xe3);
typedef struct IDirectPlaySP IDirectPlaySP, *LPDIRECTPLAYSP;
typedef BOOL (CALLBACK* LPENUMMRUCALLBACK)( LPCVOID lpData,
DWORD dwDataSize,
LPVOID lpContext );
/* For SP. Top 16 bits is dplay, bottom 16 is SP */
#define DPSP_MAJORVERSION 0x00060000
#define DPSP_DX5VERSION 0x00050000
#define DPSP_DX3VERSION 0x00040000
#define DPSP_MAJORVERSIONMASK 0xFFFF0000
#define DPSP_MINORVERSIONMASK 0x0000FFFF
/* Some flags */
#define DPLAYI_PLAYER_SYSPLAYER 0x00000001
#define DPLAYI_PLAYER_NAMESRVR 0x00000002
#define DPLAYI_PLAYER_PLAYERINGROUP 0x00000004
#define DPLAYI_PLAYER_PLAYERLOCAL 0x00000008
#define DPLAYI_GROUP_SYSGROUP 0x00000020
#define DPLAYI_GROUP_DPLAYOWNS 0x00000040
#define DPLAYI_PLAYER_APPSERVER 0x00000080
#define DPLAYI_GROUP_HIDDEN 0x00000400
/* Define the COM interface */
#define ICOM_INTERFACE IDirectPlaySP
#define IDirectPlaySP_METHODS \
ICOM_METHOD5(HRESULT,AddMRUEntry, LPCWSTR,lpSection, LPCWSTR,lpKey, LPCVOID,lpData, DWORD,dwDataSize, DWORD,dwMaxEntries ) \
ICOM_METHOD6(HRESULT,CreateAddress, REFGUID,guidSP, REFGUID,guidDataType, LPCVOID,lpData, DWORD,dwDataSize, LPVOID,lpAddress,LPDWORD,lpdwAddressSize) \
ICOM_METHOD4(HRESULT,EnumAddress, LPDPENUMADDRESSCALLBACK,lpEnumAddressCallback, LPCVOID,lpAddress, DWORD,dwAddressSize, LPVOID,lpContext ) \
ICOM_METHOD4(HRESULT,EnumMRUEntries, LPCWSTR,lpSection, LPCWSTR,lpKey, LPENUMMRUCALLBACK,lpEnumMRUCallback, LPVOID,lpContext ) \
ICOM_METHOD2(HRESULT,GetPlayerFlags, DPID,idPlayer, LPDWORD,lpdwPlayerFlags ) \
ICOM_METHOD4(HRESULT,GetSPPlayerData, DPID,idPlayer, LPVOID*,lplpData, LPDWORD,lpdwDataSize, DWORD,dwFlags ) \
ICOM_METHOD3(HRESULT,HandleMessage, LPVOID,lpMessageBody, DWORD,dwMessageBodySize, LPVOID,lpMessageHeader ) \
ICOM_METHOD4(HRESULT,SetSPPlayerData, DPID,idPlayer, LPVOID,lpData, DWORD,dwDataSize, DWORD,dwFlags ) \
ICOM_METHOD4(HRESULT,CreateCompoundAddress, LPCDPCOMPOUNDADDRESSELEMENT,lpElements, DWORD,dwElementCount, LPVOID,lpAddress, LPDWORD,lpdwAddressSize ) \
ICOM_METHOD3(HRESULT,GetSPData, LPVOID*,lplpData, LPDWORD,dwDataSize, DWORD,dwFlags ) \
ICOM_METHOD3(HRESULT,SetSPData, LPVOID,lpData, DWORD,dwDataSize, DWORD,dwFlags ) \
ICOM_METHOD2(VOID,SendComplete, LPVOID,, DWORD, )
#define IDirectPlaySP_IMETHODS \
IUnknown_IMETHODS \
IDirectPlaySP_METHODS
ICOM_DEFINE(IDirectPlaySP,IUnknown)
#undef ICOM_INTERFACE
/*** IUnknown methods ***/
#define IDirectPlaySP_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b)
#define IDirectPlaySP_AddRef(p) ICOM_CALL (AddRef,p)
#define IDirectPlaySP_Release(p) ICOM_CALL (Release,p)
/*** IDirectPlaySP methods ***/
#define IDirectPlaySP_AddMRUEntry ICOM_CALL5(AddMRUEntry,p,a,b,c,d,e)
#define IDirectPlaySP_CreateAddress ICOM_CALL6(CreateAddress,p,a,b,c,d,e,f)
#define IDirectPlaySP_EnumAddress ICOM_CALL4(EnumAddress,p,a,b,c,d)
#define IDirectPlaySP_EnumMRUEntries ICOM_CALL4(EnumMRUEntries,p,a,b,c,d)
#define IDirectPlaySP_GetPlayerFlags ICOM_CALL2(GetPlayerFlags,p,a,b)
#define IDirectPlaySP_GetSPPlayerData ICOM_CALL4(GetSPPlayerData,p,a,b,c,d)
#define IDirectPlaySP_HandleMessage ICOM_CALL3(HandleMessage,p,a,b,c)
#define IDirectPlaySP_SetSPPlayerData ICOM_CALL4(SetSPPlayerData,p,a,b,c,d)
#define IDirectPlaySP_CreateCompoundAddress ICOM_CALL4(CreateCompoundAddress,p,a,b,c,d)
#define IDirectPlaySP_GetSPData ICOM_CALL3(GetSPData,p,a,b,c)
#define IDirectPlaySP_SetSPData ICOM_CALL3(SetSPData,p,a,b,c)
#define IDirectPlaySP_SendComplete ICOM_CALL2(SendComplete,p,a,b)
/* SP Callback stuff */
typedef struct tagDPSP_ADDPLAYERTOGROUPDATA
{
DPID idPlayer;
DPID idGroup;
IDirectPlaySP* lpISP;
} DPSP_ADDPLAYERTOGROUPDATA, *LPDPSP_ADDPLAYERTOGROUPDATA;
typedef struct tagDPSP_CLOSEDATA
{
IDirectPlaySP* lpISP;
} DPSP_CLOSEDATA, *LPDPSP_CLOSEDATA;
typedef struct tagDPSP_CREATEGROUPDATA
{
DPID idGroup;
DWORD dwFlags;
LPVOID lpSPMessageHeader;
IDirectPlaySP* lpISP;
} DPSP_CREATEGROUPDATA, *LPDPSP_CREATEGROUPDATA;
typedef struct tagDPSP_CREATEPLAYERDATA
{
DPID idPlayer;
DWORD dwFlags;
LPVOID lpSPMessageHeader;
IDirectPlaySP* lpISP;
} DPSP_CREATEPLAYERDATA, *LPDPSP_CREATEPLAYERDATA;
typedef struct tagDPSP_DELETEGROUPDATA
{
DPID idGroup;
DWORD dwFlags;
IDirectPlaySP* lpISP;
} DPSP_DELETEGROUPDATA, *LPDPSP_DELETEGROUPDATA;
typedef struct tagDPSP_DELETEPLAYERDATA
{
DPID idPlayer;
DWORD dwFlags;
IDirectPlaySP* lpISP;
} DPSP_DELETEPLAYERDATA, *LPDPSP_DELETEPLAYERDATA;
typedef struct tagDPSP_ENUMSESSIONSDATA
{
LPVOID lpMessage;
DWORD dwMessageSize;
IDirectPlaySP* lpISP;
BOOL bReturnStatus;
} DPSP_ENUMSESSIONSDATA, *LPDPSP_ENUMSESSIONSDATA;
typedef struct _DPSP_GETADDRESSDATA
{
DPID idPlayer;
DWORD dwFlags;
LPDPADDRESS lpAddress;
LPDWORD lpdwAddressSize;
IDirectPlaySP* lpISP;
} DPSP_GETADDRESSDATA, *LPDPSP_GETADDRESSDATA;
typedef struct tagDPSP_GETADDRESSCHOICESDATA
{
LPDPADDRESS lpAddress;
LPDWORD lpdwAddressSize;
IDirectPlaySP* lpISP;
} DPSP_GETADDRESSCHOICESDATA, *LPDPSP_GETADDRESSCHOICESDATA;
typedef struct tagDPSP_GETCAPSDATA
{
DPID idPlayer;
LPDPCAPS lpCaps;
DWORD dwFlags;
IDirectPlaySP* lpISP;
} DPSP_GETCAPSDATA, *LPDPSP_GETCAPSDATA;
typedef struct tagDPSP_OPENDATA
{
BOOL bCreate;
LPVOID lpSPMessageHeader;
IDirectPlaySP* lpISP;
BOOL bReturnStatus;
DWORD dwOpenFlags;
DWORD dwSessionFlags;
} DPSP_OPENDATA, *LPDPSP_OPENDATA;
typedef struct tagDPSP_REMOVEPLAYERFROMGROUPDATA
{
DPID idPlayer;
DPID idGroup;
IDirectPlaySP* lpISP;
} DPSP_REMOVEPLAYERFROMGROUPDATA, *LPDPSP_REMOVEPLAYERFROMGROUPDATA;
typedef struct tagDPSP_REPLYDATA
{
LPVOID lpSPMessageHeader;
LPVOID lpMessage;
DWORD dwMessageSize;
DPID idNameServer;
IDirectPlaySP* lpISP;
} DPSP_REPLYDATA, *LPDPSP_REPLYDATA;
typedef struct tagDPSP_SENDDATA
{
DWORD dwFlags;
DPID idPlayerTo;
DPID idPlayerFrom;
LPVOID lpMessage;
DWORD dwMessageSize;
BOOL bSystemMessage;
IDirectPlaySP* lpISP;
} DPSP_SENDDATA, *LPDPSP_SENDDATA;
typedef struct tagDPSP_SENDTOGROUPDATA
{
DWORD dwFlags;
DPID idGroupTo;
DPID idPlayerFrom;
LPVOID lpMessage;
DWORD dwMessageSize;
IDirectPlaySP* lpISP;
} DPSP_SENDTOGROUPDATA, *LPDPSP_SENDTOGROUPDATA;
typedef struct tagDPSP_SENDEXDATA
{
IDirectPlaySP* lpISP;
DWORD dwFlags;
DPID idPlayerTo;
DPID idPlayerFrom;
LPSGBUFFER lpSendBuffers;
DWORD cBuffers;
DWORD dwMessageSize;
DWORD dwPriority;
DWORD dwTimeout;
LPVOID lpDPContext;
LPDWORD lpdwSPMsgID;
BOOL bSystemMessage;
} DPSP_SENDEXDATA, *LPDPSP_SENDEXDATA;
typedef struct tagDPSP_SENDTOGROUPEXDATA
{
IDirectPlaySP* lpISP;
DWORD dwFlags;
DPID idGroupTo;
DPID idPlayerFrom;
LPSGBUFFER lpSendBuffers;
DWORD cBuffers;
DWORD dwMessageSize;
DWORD dwPriority;
DWORD dwTimeout;
LPVOID lpDPContext;
LPDWORD lpdwSPMsgID;
} DPSP_SENDTOGROUPEXDATA, *LPDPSP_SENDTOGROUPEXDATA;
typedef struct tagDPSP_GETMESSAGEQUEUEDATA
{
IDirectPlaySP* lpISP;
DWORD dwFlags;
DPID idFrom;
DPID idTo;
LPDWORD lpdwNumMsgs;
LPDWORD lpdwNumBytes;
} DPSP_GETMESSAGEQUEUEDATA, *LPDPSP_GETMESSAGEQUEUEDATA;
#define DPCANCELSEND_PRIORITY 0x00000001
#define DPCANCELSEND_ALL 0x00000002
typedef struct tagDPSP_CANCELDATA
{
IDirectPlaySP* lpISP;
DWORD dwFlags;
LPRGLPVOID lprglpvSPMsgID;
DWORD cSPMsgID;
DWORD dwMinPriority;
DWORD dwMaxPriority;
} DPSP_CANCELDATA, *LPDPSP_CANCELDATA;
typedef struct tagDPSP_SHUTDOWNDATA
{
IDirectPlaySP* lpISP;
} DPSP_SHUTDOWNDATA, *LPDPSP_SHUTDOWNDATA;
/* Prototypes returned by SPInit */
typedef HRESULT (WINAPI *LPDPSP_CREATEPLAYER)(LPDPSP_CREATEPLAYERDATA);
typedef HRESULT (WINAPI *LPDPSP_DELETEPLAYER)(LPDPSP_DELETEPLAYERDATA);
typedef HRESULT (WINAPI *LPDPSP_SEND)(LPDPSP_SENDDATA);
typedef HRESULT (WINAPI *LPDPSP_ENUMSESSIONS)(LPDPSP_ENUMSESSIONSDATA);
typedef HRESULT (WINAPI *LPDPSP_REPLY)(LPDPSP_REPLYDATA);
typedef HRESULT (WINAPI *LPDPSP_SHUTDOWN)(void);
typedef HRESULT (WINAPI *LPDPSP_CREATEGROUP)(LPDPSP_CREATEGROUPDATA);
typedef HRESULT (WINAPI *LPDPSP_DELETEGROUP)(LPDPSP_DELETEGROUPDATA);
typedef HRESULT (WINAPI *LPDPSP_ADDPLAYERTOGROUP)(LPDPSP_ADDPLAYERTOGROUPDATA);
typedef HRESULT (WINAPI *LPDPSP_REMOVEPLAYERFROMGROUP)(LPDPSP_REMOVEPLAYERFROMGROUPDATA);
typedef HRESULT (WINAPI *LPDPSP_GETCAPS)(LPDPSP_GETCAPSDATA);
typedef HRESULT (WINAPI *LPDPSP_GETADDRESS)(LPDPSP_GETADDRESSDATA);
typedef HRESULT (WINAPI *LPDPSP_GETADDRESSCHOICES)(LPDPSP_GETADDRESSCHOICESDATA);
typedef HRESULT (WINAPI *LPDPSP_OPEN)(LPDPSP_OPENDATA);
typedef HRESULT (WINAPI *LPDPSP_CLOSE)(void);
typedef HRESULT (WINAPI *LPDPSP_SENDTOGROUP)(LPDPSP_SENDTOGROUPDATA);
typedef HRESULT (WINAPI *LPDPSP_SHUTDOWNEX)(LPDPSP_SHUTDOWNDATA);
typedef HRESULT (WINAPI *LPDPSP_CLOSEEX)(LPDPSP_CLOSEDATA);
typedef HRESULT (WINAPI *LPDPSP_SENDEX)(LPDPSP_SENDEXDATA);
typedef HRESULT (WINAPI *LPDPSP_SENDTOGROUPEX)(LPDPSP_SENDTOGROUPEXDATA);
typedef HRESULT (WINAPI *LPDPSP_CANCEL)(LPDPSP_CANCELDATA);
typedef HRESULT (WINAPI *LPDPSP_GETMESSAGEQUEUE)(LPDPSP_GETMESSAGEQUEUEDATA);
typedef struct tagDPSP_SPCALLBACKS
{
DWORD dwSize;
DWORD dwVersion;
LPDPSP_ENUMSESSIONS EnumSessions; /* Must be provided */
LPDPSP_REPLY Reply; /* Must be provided */
LPDPSP_SEND Send; /* Must be provided */
LPDPSP_ADDPLAYERTOGROUP AddPlayerToGroup; /* Optional */
LPDPSP_CLOSE Close; /* Optional */
LPDPSP_CREATEGROUP CreateGroup; /* Optional */
LPDPSP_CREATEPLAYER CreatePlayer; /* Optional */
LPDPSP_DELETEGROUP DeleteGroup; /* Optional */
LPDPSP_DELETEPLAYER DeletePlayer; /* Optional */
LPDPSP_GETADDRESS GetAddress; /* Optional */
LPDPSP_GETCAPS GetCaps; /* Optional */
LPDPSP_OPEN Open; /* Optional */
LPDPSP_REMOVEPLAYERFROMGROUP RemovePlayerFromGroup; /* Optional */
LPDPSP_SENDTOGROUP SendToGroup; /* Optional */
LPDPSP_SHUTDOWN Shutdown; /* Optional */
LPDPSP_CLOSEEX CloseEx; /* Optional */
LPDPSP_SHUTDOWNEX ShutdownEx; /* Optional */
LPDPSP_GETADDRESSCHOICES GetAddressChoices; /* Optional */
LPDPSP_SENDEX SendEx; /* Optional */
LPDPSP_SENDTOGROUPEX SendToGroupEx; /* Optional */
LPDPSP_CANCEL Cancel; /* Optional */
LPDPSP_GETMESSAGEQUEUE GetMessageQueue; /* Optional */
} DPSP_SPCALLBACKS, *LPDPSP_SPCALLBACKS;
typedef struct tagSPINITDATA
{
LPDPSP_SPCALLBACKS lpCB;
IDirectPlaySP* lpISP;
LPWSTR lpszName;
LPGUID lpGuid;
DWORD dwReserved1;
DWORD dwReserved2;
DWORD dwSPHeaderSize;
LPDPADDRESS lpAddress;
DWORD dwAddressSize;
DWORD dwSPVersion;
} SPINITDATA, *LPSPINITDATA;
typedef HRESULT (WINAPI *LPDPSP_SPINIT)(LPSPINITDATA);
/* This variable is exported from the DLL at ordinal 6 to be accessed by the
* SP directly
*/
extern DWORD gdwDPlaySPRefCount;
#endif

View File

@ -10,11 +10,14 @@
* dplayx.dll data which is accessible from all processes. * dplayx.dll data which is accessible from all processes.
*/ */
#include <stdio.h>
#include "debugtools.h" #include "debugtools.h"
#include "winbase.h" #include "winbase.h"
#include "winerror.h" #include "winerror.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#include "heap.h"
#include "wingdi.h"
#include "winuser.h"
#include "dplayx_global.h" #include "dplayx_global.h"
#include "dplayx_messages.h" /* For CreateMessageReceptionThread only */ #include "dplayx_messages.h" /* For CreateMessageReceptionThread only */
@ -42,9 +45,9 @@ static LPVOID lpSharedStaticData = NULL;
/* HACK for simple global data right now */ /* HACK for simple global data right now */
#define dwStaticSharedSize (128 * 1024) /* FIXME: Way too much */ #define dwStaticSharedSize (128 * 1024) /* 128 KBytes */
#define dwDynamicSharedSize (128 * 1024) /* FIXME: Enough? */ #define dwDynamicSharedSize (512 * 1024) /* 512 KBytes */
#define dwTotalSharedSize (dwStaticSharedSize + dwDynamicSharedSize) #define dwTotalSharedSize ( dwStaticSharedSize + dwDynamicSharedSize )
/* FIXME: Is there no easier way? */ /* FIXME: Is there no easier way? */
@ -53,7 +56,6 @@ static LPVOID lpSharedStaticData = NULL;
* Each block has 4 bytes which are 0 unless used */ * Each block has 4 bytes which are 0 unless used */
#define dwBlockSize 512 #define dwBlockSize 512
#define dwMaxBlock (dwDynamicSharedSize/dwBlockSize) #define dwMaxBlock (dwDynamicSharedSize/dwBlockSize)
DWORD dwBlockOn = 0;
typedef struct typedef struct
{ {
@ -61,7 +63,7 @@ typedef struct
DWORD data[dwBlockSize-sizeof(DWORD)]; DWORD data[dwBlockSize-sizeof(DWORD)];
} DPLAYX_MEM_SLICE; } DPLAYX_MEM_SLICE;
DPLAYX_MEM_SLICE* lpMemArea; static DPLAYX_MEM_SLICE* lpMemArea;
void DPLAYX_PrivHeapFree( LPVOID addr ); void DPLAYX_PrivHeapFree( LPVOID addr );
void DPLAYX_PrivHeapFree( LPVOID addr ) void DPLAYX_PrivHeapFree( LPVOID addr )
@ -81,6 +83,7 @@ void DPLAYX_PrivHeapFree( LPVOID addr )
lpMemArea[ dwBlockUsed ].used = 0; 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 DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size ) LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size )
{ {
@ -149,17 +152,19 @@ typedef struct tagDPLAYX_LOBBYDATA
/* Information for dplobby interfaces */ /* Information for dplobby interfaces */
DWORD dwAppID; DWORD dwAppID;
HANDLE hReceiveEvent;
DWORD dwAppLaunchedFromID; DWORD dwAppLaunchedFromID;
/* Should this lobby app send messages to creator at important life /* Should this lobby app send messages to creator at important life
* stages * stages
*/ */
BOOL bInformOnConnect; /* FIXME: Not used yet */ HANDLE hInformOnAppStart;
BOOL bInformOnSettingRead; HANDLE hInformOnAppDeath;
BOOL bInformOnAppDeath; /* FIXME: Not used yet */ HANDLE hInformOnSettingRead;
/* Sundries */
BOOL bWaitForConnectionSettings; BOOL bWaitForConnectionSettings;
DWORD dwLobbyMsgThreadId;
} DPLAYX_LOBBYDATA, *LPDPLAYX_LOBBYDATA; } DPLAYX_LOBBYDATA, *LPDPLAYX_LOBBYDATA;
@ -190,6 +195,7 @@ BOOL DPLAYX_ConstructData(void)
SECURITY_ATTRIBUTES s_attrib; SECURITY_ATTRIBUTES s_attrib;
BOOL bInitializeSharedMemory = FALSE; BOOL bInitializeSharedMemory = FALSE;
LPVOID lpDesiredMemoryMapStart = (LPVOID)0x50000000; LPVOID lpDesiredMemoryMapStart = (LPVOID)0x50000000;
HANDLE hInformOnStart;
TRACE( "DPLAYX dll loaded - construct called\n" ); TRACE( "DPLAYX dll loaded - construct called\n" );
@ -309,6 +315,22 @@ BOOL DPLAYX_ConstructData(void)
DPLAYX_ReleaseSemaphore(); 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 %u %s\n",
hInformOnStart, bSuccess ? "succeed" : "failed" );
/* Close out handle */
DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, TRUE );
}
return TRUE; return TRUE;
} }
@ -318,8 +340,26 @@ BOOL DPLAYX_ConstructData(void)
***************************************************************************/ ***************************************************************************/
BOOL DPLAYX_DestructData(void) BOOL DPLAYX_DestructData(void)
{ {
HANDLE hInformOnDeath;
TRACE( "DPLAYX dll unloaded - destruct called\n" ); 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 %u %s\n",
hInformOnDeath, bSuccess ? "succeed" : "failed" );
/* Close out handle */
DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, TRUE );
}
/* DO CLEAN UP (LAST) */
/* Delete the semaphore */ /* Delete the semaphore */
CloseHandle( hDplayxSema ); CloseHandle( hDplayxSema );
@ -334,9 +374,6 @@ BOOL DPLAYX_DestructData(void)
void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData ) void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData )
{ {
ZeroMemory( lpData, sizeof( *lpData ) ); ZeroMemory( lpData, sizeof( *lpData ) );
/* Set the handle to a better invalid value */
lpData->hReceiveEvent = INVALID_HANDLE_VALUE;
} }
/* NOTE: This must be called with the semaphore aquired. /* NOTE: This must be called with the semaphore aquired.
@ -370,7 +407,7 @@ BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppID, LPDPLAYX_LOBBYDATA* lplpDplData )
} }
/* Reserve a spot for the new appliction. TRUE means success and FALSE failure. */ /* Reserve a spot for the new appliction. TRUE means success and FALSE failure. */
BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent ) BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID )
{ {
UINT i; UINT i;
@ -388,16 +425,16 @@ BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent )
if( lobbyData[ i ].dwAppID == 0 ) if( lobbyData[ i ].dwAppID == 0 )
{ {
/* This process is now lobbied */ /* This process is now lobbied */
TRACE( "Setting lobbyData[%u] for (0x%08lx,%u,0x%08lx)\n", TRACE( "Setting lobbyData[%u] for (0x%08lx,0x%08lx)\n",
i, dwAppID, hReceiveEvent, GetCurrentProcessId() ); i, dwAppID, GetCurrentProcessId() );
lobbyData[ i ].dwAppID = dwAppID; lobbyData[ i ].dwAppID = dwAppID;
lobbyData[ i ].hReceiveEvent = hReceiveEvent;
lobbyData[ i ].dwAppLaunchedFromID = GetCurrentProcessId(); lobbyData[ i ].dwAppLaunchedFromID = GetCurrentProcessId();
lobbyData[ i ].bInformOnConnect = TRUE; /* FIXME: Where is the best place for this? In interface or here? */
lobbyData[ i ].bInformOnSettingRead = TRUE; lobbyData[ i ].hInformOnAppStart = 0;
lobbyData[ i ].bInformOnAppDeath = TRUE; lobbyData[ i ].hInformOnAppDeath = 0;
lobbyData[ i ].hInformOnSettingRead = 0;
DPLAYX_ReleaseSemaphore(); DPLAYX_ReleaseSemaphore();
return TRUE; return TRUE;
@ -437,14 +474,114 @@ BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID )
return FALSE; return FALSE;
} }
BOOL DPLAYX_SetLobbyHandles( DWORD dwAppID,
HANDLE hStart, HANDLE hDeath, HANDLE hConnRead )
{
LPDPLAYX_LOBBYDATA lpLData;
/* Need to explictly give lobby application. Can't set for yourself */
if( dwAppID == 0 )
{
return FALSE;
}
DPLAYX_AquireSemaphore();
if( !DPLAYX_IsAppIdLobbied( dwAppID, &lpLData ) )
{
DPLAYX_ReleaseSemaphore();
return FALSE;
}
lpLData->hInformOnAppStart = hStart;
lpLData->hInformOnAppDeath = hDeath;
lpLData->hInformOnSettingRead = hConnRead;
DPLAYX_ReleaseSemaphore();
return TRUE;
}
BOOL DPLAYX_GetThisLobbyHandles( LPHANDLE lphStart,
LPHANDLE lphDeath,
LPHANDLE lphConnRead,
BOOL bClearSetHandles )
{
LPDPLAYX_LOBBYDATA lpLData;
DPLAYX_AquireSemaphore();
if( !DPLAYX_IsAppIdLobbied( 0, &lpLData ) )
{
DPLAYX_ReleaseSemaphore();
return FALSE;
}
if( lphStart != NULL )
{
if( lpLData->hInformOnAppStart == 0 )
{
DPLAYX_ReleaseSemaphore();
return FALSE;
}
*lphStart = lpLData->hInformOnAppStart;
if( bClearSetHandles )
{
CloseHandle( lpLData->hInformOnAppStart );
lpLData->hInformOnAppStart = 0;
}
}
if( lphDeath != NULL )
{
if( lpLData->hInformOnAppDeath == 0 )
{
DPLAYX_ReleaseSemaphore();
return FALSE;
}
*lphDeath = lpLData->hInformOnAppDeath;
if( bClearSetHandles )
{
CloseHandle( lpLData->hInformOnAppDeath );
lpLData->hInformOnAppDeath = 0;
}
}
if( lphConnRead != NULL )
{
if( lpLData->hInformOnSettingRead == 0 )
{
DPLAYX_ReleaseSemaphore();
return FALSE;
}
*lphConnRead = lpLData->hInformOnSettingRead;
if( bClearSetHandles )
{
CloseHandle( lpLData->hInformOnSettingRead );
lpLData->hInformOnSettingRead = 0;
}
}
DPLAYX_ReleaseSemaphore();
return TRUE;
}
HRESULT DPLAYX_GetConnectionSettingsA HRESULT DPLAYX_GetConnectionSettingsA
( DWORD dwAppID, ( DWORD dwAppID,
LPVOID lpData, LPVOID lpData,
LPDWORD lpdwDataSize, LPDWORD lpdwDataSize )
LPBOOL lpbSendHaveReadMessage )
{ {
LPDPLAYX_LOBBYDATA lpDplData; LPDPLAYX_LOBBYDATA lpDplData;
DWORD dwRequiredDataSize = 0; DWORD dwRequiredDataSize = 0;
HANDLE hInformOnSettingRead;
DPLAYX_AquireSemaphore(); DPLAYX_AquireSemaphore();
@ -472,23 +609,33 @@ HRESULT DPLAYX_GetConnectionSettingsA
return DPERR_BUFFERTOOSMALL; return DPERR_BUFFERTOOSMALL;
} }
/* They have gotten the information */
*lpbSendHaveReadMessage = lpDplData->bInformOnSettingRead;
lpDplData->bInformOnSettingRead = FALSE;
DPLAYX_CopyConnStructA( (LPDPLCONNECTION)lpData, lpDplData->lpConn ); DPLAYX_CopyConnStructA( (LPDPLCONNECTION)lpData, lpDplData->lpConn );
DPLAYX_ReleaseSemaphore(); DPLAYX_ReleaseSemaphore();
/* They have gotten the information - signal the event if required */
if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) &&
hInformOnSettingRead
)
{
BOOL bSuccess;
bSuccess = SetEvent( hInformOnSettingRead );
TRACE( "Signalling setting read event %u %s\n",
hInformOnSettingRead, bSuccess ? "succeed" : "failed" );
/* Close out handle */
DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE );
}
return DP_OK; return DP_OK;
} }
/* Assumption: Enough contiguous space was allocated at dest */ /* Assumption: Enough contiguous space was allocated at dest */
void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src ) void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src )
{ {
BYTE* lpStartOfFreeSpace; BYTE* lpStartOfFreeSpace;
memcpy( dest, src, sizeof( DPLCONNECTION ) ); CopyMemory( dest, src, sizeof( DPLCONNECTION ) );
lpStartOfFreeSpace = ((BYTE*)dest) + sizeof( DPLCONNECTION ); lpStartOfFreeSpace = ((BYTE*)dest) + sizeof( DPLCONNECTION );
@ -497,7 +644,7 @@ void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src )
{ {
dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace; dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 ); lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
memcpy( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) ); CopyMemory( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) );
/* Session names may or may not exist */ /* Session names may or may not exist */
if( src->lpSessionDesc->sess.lpszSessionNameA ) if( src->lpSessionDesc->sess.lpszSessionNameA )
@ -505,7 +652,7 @@ void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src )
strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->sess.lpszSessionNameA ); strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->sess.lpszSessionNameA );
dest->lpSessionDesc->sess.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace; dest->lpSessionDesc->sess.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
lpStartOfFreeSpace += lpStartOfFreeSpace +=
strlen( (LPSTR)dest->lpSessionDesc->sess.lpszSessionName ) + 1; strlen( (LPSTR)dest->lpSessionDesc->sess.lpszSessionNameA ) + 1;
} }
if( src->lpSessionDesc->pass.lpszPasswordA ) if( src->lpSessionDesc->pass.lpszPasswordA )
@ -522,7 +669,7 @@ void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src )
{ {
dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace; dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
lpStartOfFreeSpace += sizeof( DPNAME ); lpStartOfFreeSpace += sizeof( DPNAME );
memcpy( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) ); CopyMemory( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) );
if( src->lpPlayerName->psn.lpszShortNameA ) if( src->lpPlayerName->psn.lpszShortNameA )
{ {
@ -546,7 +693,7 @@ void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src )
if( src->lpAddress ) if( src->lpAddress )
{ {
dest->lpAddress = (LPVOID)lpStartOfFreeSpace; dest->lpAddress = (LPVOID)lpStartOfFreeSpace;
memcpy( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize ); CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );
/* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */ /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */
} }
} }
@ -554,11 +701,11 @@ void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src )
HRESULT DPLAYX_GetConnectionSettingsW HRESULT DPLAYX_GetConnectionSettingsW
( DWORD dwAppID, ( DWORD dwAppID,
LPVOID lpData, LPVOID lpData,
LPDWORD lpdwDataSize, LPDWORD lpdwDataSize )
LPBOOL lpbSendHaveReadMessage )
{ {
LPDPLAYX_LOBBYDATA lpDplData; LPDPLAYX_LOBBYDATA lpDplData;
DWORD dwRequiredDataSize = 0; DWORD dwRequiredDataSize = 0;
HANDLE hInformOnSettingRead;
DPLAYX_AquireSemaphore(); DPLAYX_AquireSemaphore();
@ -584,14 +731,24 @@ HRESULT DPLAYX_GetConnectionSettingsW
return DPERR_BUFFERTOOSMALL; return DPERR_BUFFERTOOSMALL;
} }
/* They have gotten the information */
*lpbSendHaveReadMessage = lpDplData->bInformOnSettingRead;
lpDplData->bInformOnSettingRead = FALSE;
DPLAYX_CopyConnStructW( (LPDPLCONNECTION)lpData, lpDplData->lpConn ); DPLAYX_CopyConnStructW( (LPDPLCONNECTION)lpData, lpDplData->lpConn );
DPLAYX_ReleaseSemaphore(); DPLAYX_ReleaseSemaphore();
/* They have gotten the information - signal the event if required */
if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) &&
hInformOnSettingRead
)
{
BOOL bSuccess;
bSuccess = SetEvent( hInformOnSettingRead );
TRACE( "Signalling setting read event %u %s\n",
hInformOnSettingRead, bSuccess ? "succeed" : "failed" );
/* Close out handle */
DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE );
}
return DP_OK; return DP_OK;
} }
@ -600,7 +757,7 @@ void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src )
{ {
BYTE* lpStartOfFreeSpace; BYTE* lpStartOfFreeSpace;
memcpy( dest, src, sizeof( DPLCONNECTION ) ); CopyMemory( dest, src, sizeof( DPLCONNECTION ) );
lpStartOfFreeSpace = ( (BYTE*)dest) + sizeof( DPLCONNECTION ); lpStartOfFreeSpace = ( (BYTE*)dest) + sizeof( DPLCONNECTION );
@ -609,7 +766,7 @@ void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src )
{ {
dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace; dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 ); lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
memcpy( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) ); CopyMemory( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) );
/* Session names may or may not exist */ /* Session names may or may not exist */
if( src->lpSessionDesc->sess.lpszSessionName ) if( src->lpSessionDesc->sess.lpszSessionName )
@ -634,7 +791,7 @@ void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src )
{ {
dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace; dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
lpStartOfFreeSpace += sizeof( DPNAME ); lpStartOfFreeSpace += sizeof( DPNAME );
memcpy( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) ); CopyMemory( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) );
if( src->lpPlayerName->psn.lpszShortName ) if( src->lpPlayerName->psn.lpszShortName )
{ {
@ -658,7 +815,7 @@ void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src )
if( src->lpAddress ) if( src->lpAddress )
{ {
dest->lpAddress = (LPVOID)lpStartOfFreeSpace; dest->lpAddress = (LPVOID)lpStartOfFreeSpace;
memcpy( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize ); CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );
/* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */ /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */
} }
@ -883,7 +1040,8 @@ DWORD DPLAYX_SizeOfLobbyDataW( LPDPLCONNECTION lpConn )
LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateSessionDesc2A( LPCDPSESSIONDESC2 lpSessionSrc ) LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateSessionDesc2A( LPCDPSESSIONDESC2 lpSessionSrc )
{ {
LPDPSESSIONDESC2 lpSessionDest = LPDPSESSIONDESC2 lpSessionDest =
(LPDPSESSIONDESC2)DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, sizeof( *lpSessionSrc ) ); (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY, sizeof( *lpSessionSrc ) );
DPLAYX_CopyIntoSessionDesc2A( lpSessionDest, lpSessionSrc ); DPLAYX_CopyIntoSessionDesc2A( lpSessionDest, lpSessionSrc );
return lpSessionDest; return lpSessionDest;
@ -893,17 +1051,19 @@ LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateSessionDesc2A( LPCDPSESSIONDESC2 lpSessio
BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2 lpSessionDest, BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2 lpSessionDest,
LPCDPSESSIONDESC2 lpSessionSrc ) LPCDPSESSIONDESC2 lpSessionSrc )
{ {
memcpy( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) ); CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
if( lpSessionSrc->sess.lpszSessionNameA ) if( lpSessionSrc->sess.lpszSessionNameA )
{ {
lpSessionDest->sess.lpszSessionNameA = lpSessionDest->sess.lpszSessionNameA =
DPLAYX_strdupA( HEAP_ZERO_MEMORY, lpSessionSrc->sess.lpszSessionNameA ); HEAP_strdupA( GetProcessHeap(),
HEAP_ZERO_MEMORY, lpSessionSrc->sess.lpszSessionNameA );
} }
if( lpSessionSrc->pass.lpszPasswordA ) if( lpSessionSrc->pass.lpszPasswordA )
{ {
lpSessionDest->pass.lpszPasswordA = lpSessionDest->pass.lpszPasswordA =
DPLAYX_strdupA( HEAP_ZERO_MEMORY, lpSessionSrc->pass.lpszPasswordA ); HEAP_strdupA( GetProcessHeap(),
HEAP_ZERO_MEMORY, lpSessionSrc->pass.lpszPasswordA );
} }
return TRUE; return TRUE;
@ -1002,6 +1162,24 @@ BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void)
return bFound; return bFound;
} }
BOOL DPLAYX_SetLobbyMsgThreadId( DWORD dwAppId, DWORD dwThreadId )
{
LPDPLAYX_LOBBYDATA lpLobbyData;
DPLAYX_AquireSemaphore();
if( !DPLAYX_IsAppIdLobbied( dwAppId, &lpLobbyData ) )
{
DPLAYX_ReleaseSemaphore();
return FALSE;
}
lpLobbyData->dwLobbyMsgThreadId = dwThreadId;
DPLAYX_ReleaseSemaphore();
return TRUE;
}
/* NOTE: This is potentially not thread safe. You are not guaranteed to end up /* NOTE: This is potentially not thread safe. You are not guaranteed to end up
with the correct string printed in the case where the HRESULT is not with the correct string printed in the case where the HRESULT is not
@ -1149,7 +1327,7 @@ LPCSTR DPLAYX_HresultToString(HRESULT hr)
/* For errors not in the list, return HRESULT as a string /* For errors not in the list, return HRESULT as a string
This part is not thread safe */ This part is not thread safe */
WARN( "Unknown error 0x%08lx\n", hr ); WARN( "Unknown error 0x%08lx\n", hr );
sprintf( szTempStr, "0x%08lx", hr ); wsprintfA( szTempStr, "0x%08lx", hr );
return szTempStr; return szTempStr;
} }
} }

View File

@ -9,12 +9,10 @@ BOOL DPLAYX_DestructData(void);
HRESULT DPLAYX_GetConnectionSettingsA ( DWORD dwAppID, HRESULT DPLAYX_GetConnectionSettingsA ( DWORD dwAppID,
LPVOID lpData, LPVOID lpData,
LPDWORD lpdwDataSize, LPDWORD lpdwDataSize );
LPBOOL lpbSendHaveReadMessage );
HRESULT DPLAYX_GetConnectionSettingsW ( DWORD dwAppID, HRESULT DPLAYX_GetConnectionSettingsW ( DWORD dwAppID,
LPVOID lpData, LPVOID lpData,
LPDWORD lpdwDataSize, LPDWORD lpdwDataSize );
LPBOOL lpbSendHaveReadMessage );
HRESULT DPLAYX_SetConnectionSettingsA ( DWORD dwFlags, HRESULT DPLAYX_SetConnectionSettingsA ( DWORD dwFlags,
DWORD dwAppID, DWORD dwAppID,
@ -23,16 +21,33 @@ HRESULT DPLAYX_SetConnectionSettingsW ( DWORD dwFlags,
DWORD dwAppID, DWORD dwAppID,
LPDPLCONNECTION lpConn ); LPDPLCONNECTION lpConn );
BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent ); BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID );
BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID ); BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID );
BOOL DPLAYX_WaitForConnectionSettings( BOOL bWait ); BOOL DPLAYX_WaitForConnectionSettings( BOOL bWait );
BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void); BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void);
BOOL DPLAYX_SetLobbyHandles( DWORD dwAppID,
HANDLE hStart, HANDLE hDeath, HANDLE hConnRead );
BOOL DPLAYX_GetThisLobbyHandles( LPHANDLE lphStart,
LPHANDLE lphDeath,
LPHANDLE lphConnRead, BOOL bClearSetHandles );
LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateLocalSession( UINT* index ); LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateLocalSession( UINT* index );
BOOL DPLAYX_CopyLocalSession( UINT* index, LPDPSESSIONDESC2 lpsd ); BOOL DPLAYX_CopyLocalSession( UINT* index, LPDPSESSIONDESC2 lpsd );
void DPLAYX_SetLocalSession( LPCDPSESSIONDESC2 lpsd ); void DPLAYX_SetLocalSession( LPCDPSESSIONDESC2 lpsd );
BOOL DPLAYX_SetLobbyMsgThreadId( DWORD dwAppId, DWORD dwThreadId );
/* FIXME: This should not be here */
LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size );
void DPLAYX_PrivHeapFree( LPVOID addr );
LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str );
LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str );
/* FIXME: End shared data alloc which should be local */
/* Convert a DP or DPL HRESULT code into a string for human consumption */ /* Convert a DP or DPL HRESULT code into a string for human consumption */
LPCSTR DPLAYX_HresultToString( HRESULT hr ); LPCSTR DPLAYX_HresultToString( HRESULT hr );

View File

@ -5,19 +5,24 @@
* *
* contact <hunnise@nortelnetworks.com> * contact <hunnise@nortelnetworks.com>
*/ */
#include "winerror.h"
#include "winbase.h" #include "winbase.h"
#include "debugtools.h" #include "debugtools.h"
#include "initguid.h" #include "initguid.h" /* To define the GUIDs */
#include "dplay.h" #include "dplaysp.h"
#include "dplobby.h"
#include "dplayx_global.h" #include "dplayx_global.h"
DEFAULT_DEBUG_CHANNEL(dplay); DEFAULT_DEBUG_CHANNEL(dplay);
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
static DWORD DPLAYX_dwProcessesAttached = 0; static DWORD DPLAYX_dwProcessesAttached = 0;
/* This is a globally exported variable at ordinal 6 of DPLAYX.DLL */
DWORD gdwDPlaySPRefCount = 0; /* FIXME: Should it be initialized here? */
BOOL WINAPI DPLAYX_LibMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) BOOL WINAPI DPLAYX_LibMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
{ {
@ -59,3 +64,20 @@ BOOL WINAPI DPLAYX_LibMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReser
return TRUE; return TRUE;
} }
/***********************************************************************
* DllCanUnloadNow (DPLAYX.10)
*/
HRESULT WINAPI DPLAYX_DllCanUnloadNow(void)
{
HRESULT hr = ( gdwDPlaySPRefCount > 0 ) ? S_FALSE : S_OK;
/* FIXME: Should I be putting a check in for class factory objects
* as well
*/
TRACE( ": returning 0x%08lx\n", hr );
return hr;
}

View File

@ -9,48 +9,130 @@
#include "winbase.h" #include "winbase.h"
#include "debugtools.h" #include "debugtools.h"
#include "wingdi.h"
#include "winuser.h"
#include "dplayx_messages.h" #include "dplayx_messages.h"
DEFAULT_DEBUG_CHANNEL(dplay) DEFAULT_DEBUG_CHANNEL(dplay)
typedef struct tagMSGTHREADINFO
{
HANDLE hStart;
HANDLE hDeath;
HANDLE hSettingRead;
HANDLE hNotifyEvent;
} MSGTHREADINFO, *LPMSGTHREADINFO;
static DWORD CALLBACK DPLAYX_MSG_ThreadMain( LPVOID lpContext );
static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext );
/* Create the message reception thread to allow the application to receive /* Create the message reception thread to allow the application to receive
* asynchronous message reception * asynchronous message reception
*/ */
DWORD CreateMessageReceptionThread( HANDLE hNotifyEvent ) DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
HANDLE hDeath, HANDLE hConnRead )
{ {
DWORD dwMsgThreadId; DWORD dwMsgThreadId;
LPMSGTHREADINFO lpThreadInfo;
if( !DuplicateHandle( 0, hNotifyEvent, 0, NULL, 0, FALSE, 0 ) ) lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) );
if( lpThreadInfo == NULL )
{ {
ERR( "Unable to duplicate event handle\n" );
return 0; return 0;
} }
/* FIXME: Should most likely store that thread handle */ /* The notify event may or may not exist. Depends if async comm or not */
CreateThread( NULL, /* Security attribs */ if( hNotifyEvent &&
0, /* Stack */ !DuplicateHandle( GetCurrentProcess(), hNotifyEvent,
DPLAYX_MSG_ThreadMain, /* Msg reception function */ GetCurrentProcess(), &lpThreadInfo->hNotifyEvent,
(LPVOID)hNotifyEvent, /* Msg reception function parameter */ 0, FALSE, DUPLICATE_SAME_ACCESS ) )
0, /* Flags */ {
&dwMsgThreadId /* Updated with thread id */ ERR( "Unable to duplicate event handle\n" );
); goto error;
}
/* These 3 handles don't need to be duplicated because we don't keep a
* reference to them where they're created. They're created specifically
* for the message thread
*/
lpThreadInfo->hStart = hStart;
lpThreadInfo->hDeath = hDeath;
lpThreadInfo->hSettingRead = hConnRead;
if( !CreateThread( NULL, /* Security attribs */
0, /* Stack */
DPL_MSG_ThreadMain, /* Msg reception function */
lpThreadInfo, /* Msg reception func parameter */
0, /* Flags */
&dwMsgThreadId /* Updated with thread id */
)
)
{
ERR( "Unable to create msg thread\n" );
goto error;
}
/* FIXME: Should I be closing the handle to the thread or does that
terminate the thread? */
return dwMsgThreadId; return dwMsgThreadId;
error:
HeapFree( GetProcessHeap(), 0, lpThreadInfo );
return 0;
} }
static DWORD CALLBACK DPLAYX_MSG_ThreadMain( LPVOID lpContext )
static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext )
{ {
HANDLE hMsgEvent = (HANDLE)lpContext; LPMSGTHREADINFO lpThreadInfo = (LPMSGTHREADINFO)lpContext;
DWORD dwWaitResult;
TRACE( "Msg thread created. Waiting on app startup\n" );
/* Wait to ensure that the lobby application is started w/ 1 min timeout */
dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ );
if( dwWaitResult == WAIT_TIMEOUT )
{
FIXME( "Should signal app/wait creation failure (0x%08lx)\n", dwWaitResult );
goto end_of_thread;
}
/* Close this handle as it's not needed anymore */
CloseHandle( lpThreadInfo->hStart );
lpThreadInfo->hStart = 0;
/* Wait until the lobby knows what it is */
dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE );
if( dwWaitResult == WAIT_TIMEOUT )
{
ERR( "App Read connection setting timeout fail (0x%08lx)\n", dwWaitResult );
}
/* Close this handle as it's not needed anymore */
CloseHandle( lpThreadInfo->hSettingRead );
lpThreadInfo->hSettingRead = 0;
TRACE( "App created && intialized starting main message reception loop\n" );
for ( ;; ) for ( ;; )
{ {
FIXME( "Ho Hum. Msg thread with nothing to do on handle %u\n", hMsgEvent ); MSG lobbyMsg;
#ifdef STRICT
HANDLE hNullHandle = NULL;
#else
HANDLE hNullHandle = 0;
#endif
SleepEx( 10000, FALSE ); /* 10 secs */ GetMessageW( &lobbyMsg, hNullHandle, 0, 0 );
} }
CloseHandle( hMsgEvent ); end_of_thread:
TRACE( "Msg thread exiting!\n" );
HeapFree( GetProcessHeap(), 0, lpThreadInfo );
return 0;
} }

View File

@ -1,10 +1,136 @@
#ifndef __WINE_DPLAYX_MESSAGES #ifndef __WINE_DPLAYX_MESSAGES__
#define __WINE_DPLAYX_MESSAGES #define __WINE_DPLAYX_MESSAGES__
#include "windef.h" #include "windef.h"
#include "dplay.h"
#include "rpc.h" /* For GUID */
DWORD CreateMessageReceptionThread( HANDLE hNotifyEvent ); DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
HANDLE hDeath, HANDLE hConnRead );
/* Message types etc. */
#include "pshpack1.h"
/* Non provided messages for DPLAY - guess work which may be wrong :( */
#define DPMSGCMD_ENUMSESSIONSREPLY 1
#define DPMSGCMD_ENUMSESSIONSREQUEST 2
#define DPMSGCMD_GETSETNAMETABLE 3 /* Request info from NS about
existing players/groups etc. Is
also used for reply */
#define DPMSGCMD_REQUESTNEWPLAYERID 5
#define DPMSGCMD_NEWPLAYERIDREPLY 7
#define DPMSGCMD_CREATESESSION 8
#define DPMSGCMD_CREATENEWPLAYER 9
#define DPMSGCMD_SYSTEMMESSAGE 10
#define DPMSGCMD_DELETEGROUP 12
#define DPMSGCMD_ENUMGROUPS 17
/* This is what DP 6 defines it as. Don't know what it means. All messages
* defined below are DPMSGVER_DP6.
*/
#define DPMSGVER_DP6 11
/* MAGIC number at the start of all dplay packets ("play" in ASCII) */
#define DPMSGMAGIC_DPLAYMSG 0x79616c70
/* All messages sent from the system are sent with this at the beginning of
* the message.
*/
/* Size is 4 bytes */
typedef struct tagDPMSG_SENDENVELOPE
{
DWORD dwMagic;
WORD wCommandId;
WORD wVersion;
} DPMSG_SENDENVELOPE, *LPDPMSG_SENDENVELOPE;
typedef const DPMSG_SENDENVELOPE* LPCDPMSG_SENDENVELOPE;
typedef struct tagDPMSG_SYSMSGENVELOPE
{
DWORD dwPlayerFrom;
DWORD dwPlayerTo;
} DPMSG_SYSMSGENVELOPE, *LPDPMSG_SYSMSGENVELOPE;
typedef const DPMSG_SYSMSGENVELOPE* LPCDPMSG_SYSMSGENVELOPE;
typedef struct tagDPMSG_ENUMSESSIONSREPLY
{
DPMSG_SENDENVELOPE envelope;
#if 0
DWORD dwSize; /* Size of DPSESSIONDESC2 struct */
DWORD dwFlags; /* Sessions flags */
GUID guidInstance; /* Not 100% sure this is what it is... */
GUID guidApplication;
DWORD dwMaxPlayers;
DWORD dwCurrentPlayers;
BYTE unknown[36];
#else
DPSESSIONDESC2 sd;
#endif
DWORD dwUnknown; /* Seems to be equal to 0x5c which is a "\\" */
/* Encryption package string? */
/* At the end we have ... */
/* WCHAR wszSessionName[1]; Var length with NULL terminal */
} DPMSG_ENUMSESSIONSREPLY, *LPDPMSG_ENUMSESSIONSREPLY;
typedef const DPMSG_ENUMSESSIONSREPLY* LPCDPMSG_ENUMSESSIONSREPLY;
typedef struct tagDPMSG_ENUMSESSIONSREQUEST
{
DPMSG_SENDENVELOPE envelope;
GUID guidApplication;
DWORD dwPasswordSize; /* A Guess. This is normally 0x00000000. */
/* This might be the name server DPID which
is needed for the reply */
DWORD dwFlags; /* dwFlags from EnumSessions */
} DPMSG_ENUMSESSIONSREQUEST, *LPDPMSG_ENUMSESSIONSREQUEST;
typedef const DPMSG_ENUMSESSIONSREQUEST* LPCDPMSG_ENUMSESSIONSREQUEST;
/* Size is 146 received - with 18 or 20 bytes header = ~128 bytes */
typedef struct tagDPMSG_CREATESESSION
{
DPMSG_SENDENVELOPE envelope;
} DPMSG_CREATESESSION, *LPDPMSG_CREATESESSION;
typedef const DPMSG_CREATESESSION* LPCDPMSG_CREATESESSION;
/* 28 bytes - ~18 header ~= 10 bytes msg */
typedef struct tagDPMSG_REQUESTNEWPLAYERID
{
DPMSG_SENDENVELOPE envelope;
} DPMSG_REQUESTNEWPLAYERID, *LPDPMSG_REQUESTNEWPLAYERID;
typedef const DPMSG_REQUESTNEWPLAYERID* LPCDPMSG_REQUESTNEWPLAYERID;
/* 64 byte - ~18 header ~= 46 bytes msg */
typedef struct tagDPMSG_NEWPLAYERIDREPLY
{
DPMSG_SENDENVELOPE envelope;
} DPMSG_NEWPLAYERIDREPLY, *LPDPMSG_NEWPLAYERIDREPLY;
typedef const DPMSG_NEWPLAYERIDREPLY* LPCDPMSG_NEWPLAYERIDREPLY;
#include "poppack.h"
#endif #endif

View File

@ -7,6 +7,8 @@
#ifndef __WINE_DPLAYX_QUEUE_H #ifndef __WINE_DPLAYX_QUEUE_H
#define __WINE_DPLAYX_QUEUE_H #define __WINE_DPLAYX_QUEUE_H
#include "winbase.h"
#define DPQ_INSERT(a,b,c) DPQ_INSERT_IN_TAIL(a,b,c) #define DPQ_INSERT(a,b,c) DPQ_INSERT_IN_TAIL(a,b,c)
/* /*
@ -33,6 +35,19 @@ do{ \
(head).lpQHLast = &(head).lpQHFirst; \ (head).lpQHLast = &(head).lpQHFirst; \
} while(0) } while(0)
/* Front of the queue */
#define DPQ_FIRST( head ) ( (head).lpQHFirst )
/* Check if the queue has any elements */
#define DPQ_IS_EMPTY( head ) ( DPQ_FIRST(head) == NULL )
/* Next entry -- FIXME: Convert everything over to this macro ... */
#define DPQ_NEXT( elem ) (elem).lpQNext
#define DPQ_IS_ENDOFLIST( elem ) \
( DPQ_NEXT(elem) == NULL )
/* Insert element at end of queue */
#define DPQ_INSERT_IN_TAIL(head, elm, field) \ #define DPQ_INSERT_IN_TAIL(head, elm, field) \
do { \ do { \
(elm)->field.lpQNext = NULL; \ (elm)->field.lpQNext = NULL; \
@ -41,6 +56,7 @@ do { \
(head).lpQHLast = &(elm)->field.lpQNext; \ (head).lpQHLast = &(elm)->field.lpQNext; \
} while(0) } while(0)
/* Remove element from the queue */
#define DPQ_REMOVE(head, elm, field) \ #define DPQ_REMOVE(head, elm, field) \
do { \ do { \
if (((elm)->field.lpQNext) != NULL) \ if (((elm)->field.lpQNext) != NULL) \
@ -53,18 +69,20 @@ do { \
/* head - pointer to DPQ_HEAD struct /* head - pointer to DPQ_HEAD struct
* elm - how to find the next element * elm - how to find the next element
* field - to be concatenated to rc to compare with fieldToEqual * field - to be concatenated to rc to compare with fieldToCompare
* fieldToEqual - The value that we're looking for * fieldToCompare - The value that we're comparing against
* fieldCompareOperator - The logical operator to compare field and
* fieldToCompare.
* rc - Variable to put the return code. Same type as (head).lpQHFirst * rc - Variable to put the return code. Same type as (head).lpQHFirst
*/ */
#define DPQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc ) \ #define DPQ_FIND_ENTRY( head, elm, field, fieldCompareOperator, fieldToCompare, rc )\
do { \ do { \
(rc) = (head).lpQHFirst; /* NULL head? */ \ (rc) = (head).lpQHFirst; /* NULL head? */ \
\ \
while( rc ) \ while( rc ) \
{ \ { \
/* What we're searching for? */ \ /* What we're searching for? */ \
if( (rc)->field == (fieldToEqual) ) \ if( (rc)->field fieldCompareOperator (fieldToCompare) ) \
{ \ { \
break; /* rc == correct element */ \ break; /* rc == correct element */ \
} \ } \
@ -81,12 +99,14 @@ do { \
/* head - pointer to DPQ_HEAD struct /* head - pointer to DPQ_HEAD struct
* elm - how to find the next element * elm - how to find the next element
* field - to be concatenated to rc to compare with fieldToEqual * field - to be concatenated to rc to compare with fieldToEqual
* fieldToEqual - The value that we're looking for * fieldToCompare - The value that we're comparing against
* fieldCompareOperator - The logical operator to compare field and
* fieldToCompare.
* rc - Variable to put the return code. Same type as (head).lpQHFirst * rc - Variable to put the return code. Same type as (head).lpQHFirst
*/ */
#define DPQ_REMOVE_ENTRY( head, elm, field, fieldToEqual, rc ) \ #define DPQ_REMOVE_ENTRY( head, elm, field, fieldCompareOperator, fieldToCompare, rc )\
do { \ do { \
DPQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc ); \ DPQ_FIND_ENTRY( head, elm, field, fieldCompareOperator, fieldToCompare, rc );\
\ \
/* Was the element found? */ \ /* Was the element found? */ \
if( rc ) \ if( rc ) \
@ -95,4 +115,24 @@ do { \
} \ } \
} while(0) } while(0)
/* Delete the entire queue
* head - pointer to the head of the queue
* field - field to access the next elements of the queue
* type - type of the pointer to the element element
* df - a delete function to be called. Declared with DPQ_DECL_DELETECB.
*/
#define DPQ_DELETEQ( head, field, type, df ) \
while( !DPQ_IS_EMPTY(head) ) \
{ \
type holder = (head).lpQHFirst; \
DPQ_REMOVE( head, holder, field ); \
df( holder ); \
}
/* How to define the method to be passed to DPQ_DELETEQ */
#define DPQ_DECL_DELETECB( name, type ) void name( type elem )
/* Prototype of a method which just performs a HeapFree on the elem */
DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID );
#endif /* __WINE_DPLAYX_QUEUE_H */ #endif /* __WINE_DPLAYX_QUEUE_H */

File diff suppressed because it is too large Load Diff

View File

@ -10,101 +10,190 @@
#include "winbase.h" #include "winbase.h"
#include "debugtools.h" #include "debugtools.h"
#include "heap.h"
#include "dplayx_global.h" #include "dplayx_global.h"
#include "name_server.h" #include "name_server.h"
#include "dplaysp.h"
#include "dplayx_messages.h"
#include "dplayx_queue.h"
/* FIXME: Need to aquire the interface semaphore before didlling data */ /* Can't seem to solve unresolved reference even with import */
#define HACK_TIMEGETTIME
#if defined( HACK_TIMEGETTIME )
static DWORD timeGetTime(void);
#else
#include "mmsystem.h"
#endif
/* FIXME: Need to create a crit section, store and use it */
DEFAULT_DEBUG_CHANNEL(dplay); DEFAULT_DEBUG_CHANNEL(dplay);
/* NS specific structures */ /* NS specific structures */
typedef struct tagNSCacheData struct NSCacheData
{ {
struct tagNSCacheData* next; DPQ_ENTRY(NSCacheData) next;
DWORD dwTime; /* Time at which data was last known valid */
LPDPSESSIONDESC2 data; LPDPSESSIONDESC2 data;
} NSCacheData, *lpNSCacheData; LPVOID lpNSAddrHdr;
typedef struct tagNSCache };
typedef struct NSCacheData NSCacheData, *lpNSCacheData;
struct NSCache
{ {
lpNSCacheData present; /* keep track of what is to be looked at */ lpNSCacheData present; /* keep track of what is to be looked at when walking */
lpNSCacheData first;
} NSCache, *lpNSCache;
/* Local Prototypes */
static void NS_InvalidateSessionCache( lpNSCache lpCache );
DPQ_HEAD(NSCacheData) first;
};
typedef struct NSCache NSCache, *lpNSCache;
/* Name Server functions /* Name Server functions
* --------------------- * ---------------------
*/ */
void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd ) void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd )
{ {
#if 0
DPLAYX_SetLocalSession( lpsd ); DPLAYX_SetLocalSession( lpsd );
#endif
}
/* Store the given NS remote address for future reference */
void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr,
DWORD dwHdrSize,
LPDPMSG_ENUMSESSIONSREPLY lpMsg,
LPVOID lpNSInfo )
{
lpNSCache lpCache = (lpNSCache)lpNSInfo;
lpNSCacheData lpCacheNode;
TRACE( "%p, %p, %p\n", lpNSAddrHdr, lpMsg, lpNSInfo );
/* FIXME: Should check to see if the reply is for an existing session. If
* so we just update the contents and update the timestamp.
*/
lpCacheNode = (lpNSCacheData)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( *lpCacheNode ) );
if( lpCacheNode == NULL )
{
ERR( "no memory for NS node\n" );
return;
}
lpCacheNode->lpNSAddrHdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
dwHdrSize );
CopyMemory( lpCacheNode->lpNSAddrHdr, lpNSAddrHdr, dwHdrSize );
lpCacheNode->data = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof( *lpCacheNode->data ) );
if( lpCacheNode->data == NULL )
{
ERR( "no memory for SESSIONDESC2\n" );
return;
}
CopyMemory( lpCacheNode->data, &lpMsg->sd, sizeof( *lpCacheNode->data ) );
lpCacheNode->data->sess.lpszSessionNameA = HEAP_strdupWtoA( GetProcessHeap(),
HEAP_ZERO_MEMORY,
(LPWSTR)(lpMsg+1) );
lpCacheNode->dwTime = timeGetTime();
DPQ_INSERT(lpCache->first, lpCacheNode, next );
lpCache->present = lpCacheNode;
/* Use this message as an oportunity to weed out any old sessions so
* that we don't enum them again
*/
NS_PruneSessionCache( lpNSInfo );
}
LPVOID NS_GetNSAddr( LPVOID lpNSInfo )
{
lpNSCache lpCache = (lpNSCache)lpNSInfo;
FIXME( ":quick stub\n" );
/* Ok. Cheat and don't search for the correct stuff just take the first.
* FIXME: In the future how are we to know what is _THE_ enum we used?
*/
return lpCache->first.lpQHFirst->lpNSAddrHdr;
} }
/* This function is responsible for sending a request for all other known /* This function is responsible for sending a request for all other known
nameservers to send us what sessions they have registered locally nameservers to send us what sessions they have registered locally
*/ */
void NS_SendSessionRequestBroadcast( LPVOID lpNSInfo ) HRESULT NS_SendSessionRequestBroadcast( LPCGUID lpcGuid,
DWORD dwFlags,
LPSPINITDATA lpSpData )
{ {
UINT index = 0; DPSP_ENUMSESSIONSDATA data;
lpNSCache lpCache = (lpNSCache)lpNSInfo; LPDPMSG_ENUMSESSIONSREQUEST lpMsg;
LPDPSESSIONDESC2 lpTmp = NULL;
/* Invalidate the session cache for the interface */ TRACE( "enumerating for guid %s\n", debugstr_guid( lpcGuid ) );
NS_InvalidateSessionCache( lpCache );
/* Add the local known sessions to the cache */
if( ( lpTmp = DPLAYX_CopyAndAllocateLocalSession( &index ) ) != NULL )
{
lpCache->first = (lpNSCacheData)HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof( *(lpCache->first) ) );
lpCache->first->data = lpTmp;
lpCache->first->next = NULL;
lpCache->present = lpCache->first;
while( ( lpTmp = DPLAYX_CopyAndAllocateLocalSession( &index ) ) != NULL ) /* Get the SP to deal with sending the EnumSessions request */
{ FIXME( ": not all data fields are correct\n" );
lpCache->present->next = (lpNSCacheData)HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof( *(lpCache->present) ) );
lpCache->present = lpCache->present->next;
lpCache->present->data = lpTmp;
lpCache->present->next = NULL;
}
lpCache->present = lpCache->first; data.dwMessageSize = lpSpData->dwSPHeaderSize + sizeof( *lpMsg ); /*FIXME!*/
} data.lpMessage = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
data.dwMessageSize );
data.lpISP = lpSpData->lpISP;
data.bReturnStatus = (dwFlags & DPENUMSESSIONS_RETURNSTATUS) ? TRUE : FALSE;
/* Send out requests for matching sessions to all other known computers */
FIXME( ": no remote requests sent\n" ); lpMsg = (LPDPMSG_ENUMSESSIONSREQUEST)(((BYTE*)data.lpMessage)+lpSpData->dwSPHeaderSize);
/* FIXME - how to handle responses to messages anyways? */
/* Setup EnumSession reqest message */
lpMsg->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
lpMsg->envelope.wCommandId = DPMSGCMD_ENUMSESSIONSREQUEST;
lpMsg->envelope.wVersion = DPMSGVER_DP6;
lpMsg->dwPasswordSize = 0; /* FIXME: If enumerating passwords..? */
lpMsg->dwFlags = dwFlags;
CopyMemory( &lpMsg->guidApplication, lpcGuid, sizeof( *lpcGuid ) );
return (lpSpData->lpCB->EnumSessions)( &data );
} }
/* Render all data in a session cache invalid */ DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData );
static void NS_InvalidateSessionCache( lpNSCache lpCache ) DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData )
{ {
/* FIXME: Memory leak on data (contained ptrs) */
HeapFree( GetProcessHeap(), 0, elem->data );
HeapFree( GetProcessHeap(), 0, elem->lpNSAddrHdr );
HeapFree( GetProcessHeap(), 0, elem );
}
/* Render all data in a session cache invalid */
void NS_InvalidateSessionCache( LPVOID lpNSInfo )
{
lpNSCache lpCache = (lpNSCache)lpNSInfo;
if( lpCache == NULL ) if( lpCache == NULL )
{ {
ERR( ": invalidate non existant cache\n" ); ERR( ": invalidate non existant cache\n" );
return; return;
} }
/* Remove everything from the cache */ DPQ_DELETEQ( lpCache->first, next, lpNSCacheData, cbDeleteNSNodeFromHeap );
while( lpCache->first )
{
lpCache->present = lpCache->first;
lpCache->first = lpCache->first->next;
HeapFree( GetProcessHeap(), 0, lpCache->present );
}
/* NULL out the cache pointers */ /* NULL out the walking pointer */
lpCache->present = NULL; lpCache->present = NULL;
lpCache->first = NULL;
} }
/* Create and initialize a session cache */ /* Create and initialize a session cache */
@ -121,7 +210,8 @@ BOOL NS_InitializeSessionCache( LPVOID* lplpNSInfo )
return FALSE; return FALSE;
} }
lpCache->first = lpCache->present = NULL; DPQ_INIT(lpCache->first);
lpCache->present = NULL;
return TRUE; return TRUE;
} }
@ -136,7 +226,7 @@ void NS_DeleteSessionCache( LPVOID lpNSInfo )
void NS_ResetSessionEnumeration( LPVOID lpNSInfo ) void NS_ResetSessionEnumeration( LPVOID lpNSInfo )
{ {
((lpNSCache)lpNSInfo)->present = ((lpNSCache)lpNSInfo)->first; ((lpNSCache)lpNSInfo)->present = ((lpNSCache)lpNSInfo)->first.lpQHFirst;
} }
LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo ) LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo )
@ -144,6 +234,8 @@ LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo )
LPDPSESSIONDESC2 lpSessionDesc; LPDPSESSIONDESC2 lpSessionDesc;
lpNSCache lpCache = (lpNSCache)lpNSInfo; lpNSCache lpCache = (lpNSCache)lpNSInfo;
/* FIXME: The pointers could disappear when walking if a prune happens */
/* Test for end of the list */ /* Test for end of the list */
if( lpCache->present == NULL ) if( lpCache->present == NULL )
{ {
@ -153,7 +245,93 @@ LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo )
lpSessionDesc = lpCache->present->data; lpSessionDesc = lpCache->present->data;
/* Advance tracking pointer */ /* Advance tracking pointer */
lpCache->present = lpCache->present->next; lpCache->present = lpCache->present->next.lpQNext;
return lpSessionDesc; return lpSessionDesc;
} }
/* This method should check to see if there are any sessions which are
* older than the criteria. If so, just delete that information.
*/
void NS_PruneSessionCache( LPVOID lpNSInfo )
{
lpNSCache lpCache = lpNSInfo;
lpNSCacheData lpCacheEntry;
DWORD dwPresentTime = timeGetTime();
#if defined( HACK_TIMEGETTIME )
DWORD dwPruneTime = dwPresentTime - 2; /* One iteration with safety */
#else
DWORD dwPruneTime = dwPresentTime - 10000 /* 10 secs? */;
#endif
FIXME( ": semi stub\n" );
/* FIXME: This doesn't handle time roll over correctly */
/* FIXME: Session memory leak on delete */
do
{
DPQ_FIND_ENTRY( lpCache->first, next, dwTime, <=, dwPruneTime, lpCacheEntry );
}
while( lpCacheEntry != NULL );
}
/* Message stuff */
void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg,
LPDPSP_REPLYDATA lpReplyData,
IDirectPlay2Impl* lpDP )
{
LPDPMSG_ENUMSESSIONSREPLY rmsg;
DWORD dwVariableSize;
DWORD dwVariableLen;
LPWSTR string;
/* LPDPMSG_ENUMSESSIONSREQUEST msg = (LPDPMSG_ENUMSESSIONSREQUEST)lpMsg; */
BOOL bAnsi = TRUE; /* FIXME: This needs to be in the DPLAY interface */
FIXME( ": few fixed + need to check request for response\n" );
dwVariableLen = bAnsi ? lstrlenA( lpDP->dp2->lpSessionDesc->sess.lpszSessionNameA ) + 1
: lstrlenW( lpDP->dp2->lpSessionDesc->sess.lpszSessionName ) + 1;
dwVariableSize = dwVariableLen * sizeof( WCHAR );
lpReplyData->dwMessageSize = lpDP->dp2->spData.dwSPHeaderSize +
sizeof( *rmsg ) + dwVariableSize;
lpReplyData->lpMessage = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
lpReplyData->dwMessageSize );
rmsg = (LPDPMSG_ENUMSESSIONSREPLY)lpReplyData->lpMessage;
rmsg->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
rmsg->envelope.wCommandId = DPMSGCMD_ENUMSESSIONSREPLY;
rmsg->envelope.wVersion = DPMSGVER_DP6;
CopyMemory( &rmsg->sd, lpDP->dp2->lpSessionDesc,
sizeof( lpDP->dp2->lpSessionDesc->dwSize ) );
rmsg->dwUnknown = 0x0000005c;
if( bAnsi )
{
string = HEAP_strdupAtoW( GetProcessHeap(), 0,
lpDP->dp2->lpSessionDesc->sess.lpszSessionNameA );
/* FIXME: Memory leak */
}
else
{
string = lpDP->dp2->lpSessionDesc->sess.lpszSessionName;
}
lstrcpyW( (LPWSTR)rmsg+1, string );
}
#if defined( HACK_TIMEGETTIME )
DWORD timeGetTime(void)
{
static DWORD time = 0;
return time++;
}
#endif

View File

@ -3,14 +3,33 @@
#define __WINE_DPLAYX_NAMESERVER #define __WINE_DPLAYX_NAMESERVER
#include "dplay.h" #include "dplay.h"
#include "dplaysp.h"
#include "dplayx_messages.h"
#include "dplay_global.h"
void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd ); void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd );
void NS_SendSessionRequestBroadcast( LPVOID lpNSInfo ); void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr,
DWORD dwHdrSize,
LPDPMSG_ENUMSESSIONSREPLY lpMsg,
LPVOID lpNSInfo );
LPVOID NS_GetNSAddr( LPVOID lpNSInfo );
void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg,
LPDPSP_REPLYDATA lpReplyData,
IDirectPlay2Impl* lpDP );
HRESULT NS_SendSessionRequestBroadcast( LPCGUID lpcGuid,
DWORD dwFlags,
LPSPINITDATA lpSpData );
BOOL NS_InitializeSessionCache( LPVOID* lplpNSInfo ); BOOL NS_InitializeSessionCache( LPVOID* lplpNSInfo );
void NS_DeleteSessionCache( LPVOID lpNSInfo ); void NS_DeleteSessionCache( LPVOID lpNSInfo );
void NS_InvalidateSessionCache( LPVOID lpNSInfo );
void NS_ResetSessionEnumeration( LPVOID lpNSInfo ); void NS_ResetSessionEnumeration( LPVOID lpNSInfo );
LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo ); LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo );
void NS_PruneSessionCache( LPVOID lpNSInfo );
#endif /* __WINE_DPLAYX_NAMESERVER */ #endif /* __WINE_DPLAYX_NAMESERVER */

View File

@ -13,6 +13,13 @@ extern "C" {
#include "pshpack1.h" #include "pshpack1.h"
typedef LPVOID (*LPRGLPVOID)[];
typedef LPRGLPVOID PRGPVOID, LPRGPVOID, PRGLPVOID, PAPVOID, LPAPVOID, PALPVOID, LPALPVOID;
#define VOL volatile
typedef VOID *VOL LPVOIDV;
/***************************************************************************** /*****************************************************************************
* Predeclare the interfaces * Predeclare the interfaces
*/ */
@ -283,6 +290,13 @@ typedef struct tagDPCHAT
}msgstr; }msgstr;
} DPCHAT, *LPDPCHAT; } DPCHAT, *LPDPCHAT;
typedef struct
{
UINT len;
PUCHAR pData;
} SGBUFFER, *PSGBUFFER, *LPSGBUFFER;
typedef struct tagDPSECURITYDESC typedef struct tagDPSECURITYDESC
{ {
DWORD dwSize; /* Size of structure */ DWORD dwSize; /* Size of structure */
@ -342,14 +356,7 @@ typedef BOOL CALLBACK (*LPDPENUMDPCALLBACKA)(
DWORD dwMinorVersion, /* Minor # of driver spec in lpguidSP */ DWORD dwMinorVersion, /* Minor # of driver spec in lpguidSP */
LPVOID lpContext); /* User given */ LPVOID lpContext); /* User given */
/* NOTE: This isn't in the dplay.h header file, but this shouldn't be
* a problem. We require this because we include all these header files
* which declare GUIDs in guid.c
*/
#ifndef __LPCGUID_DEFINED__
#define __LPCGUID_DEFINED__
typedef const GUID *LPCGUID; typedef const GUID *LPCGUID;
#endif
typedef const DPNAME *LPCDPNAME; typedef const DPNAME *LPCDPNAME;

View File

@ -6,7 +6,6 @@ VPATH = @srcdir@
MODULE = ole MODULE = ole
C_SRCS = \ C_SRCS = \
guid.c \
ole2nls.c ole2nls.c
EXTRASUBDIRS = nls EXTRASUBDIRS = nls

View File

@ -1,32 +0,0 @@
#define INITGUID
/* FIXME: we include all the header files containing GUIDs
* so that the corresponding variables get defined. But they
* don't even all belong to the same DLL !!!
*
* Therefore, as the builtin DLL's get teased apart (e.g. for elf-dlls)
* then this file will have to be partitioned into per dll files.
*/
#include "initguid.h"
#if 0
#include "shlguid.h"
#include "docobj.h"
#include "olectl.h"
#include "oleidl.h"
#include "oaidl.h"
#include "ocidl.h"
#include "objbase.h"
#include "servprov.h"
#include "ddraw.h"
#include "d3d.h"
#include "dinput.h"
#include "dsound.h"
#include "dplay.h"
#include "dplobby.h"
#include "vfw.h"
#include "shlobj.h"
#endif
/* and now for the one assumed GUID... */
DEFINE_GUID(GUID_NULL, 0,0,0,0,0,0,0,0,0,0,0);