Commit 72526ba4 authored by Peter Hunnisett's avatar Peter Hunnisett Committed by Alexandre Julliard

- Remove winmm hack in dplay code

- Fix up some missing holes in the code - More message implementation - Status documentation update
parent a387aa48
......@@ -380,7 +380,7 @@ crtdll/libcrtdll.so: libkernel32.so
ddraw/libddraw.so: libole32.so libuser32.so libx11drv.so libgdi32.so libkernel32.so
dinput/libdinput.so: libuser32.so libkernel32.so
dplay/libdplay.so: libdplayx.so
dplayx/libdplayx.so: libole32.so libadvapi32.so libkernel32.so
dplayx/libdplayx.so: libwinmm.so libole32.so libadvapi32.so libkernel32.so
dsound/libdsound.so: libwinmm.so libkernel32.so
gdi/libgdi32.so: libkernel32.so
icmp/libicmp.so: libkernel32.so
......
......@@ -4,7 +4,7 @@ SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = dplayx
SOVERSION = 1.0
IMPORTS = ole32 advapi32 kernel32
IMPORTS = winmm ole32 advapi32 kernel32
C_SRCS = \
dpclassfactory.c \
......
......@@ -622,6 +622,8 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
This, lpMessageBody, dwMessageBodySize, lpMessageHeader, wCommandId,
wVersion );
DebugBreak();
switch( wCommandId )
{
case DPMSGCMD_REQUESTNEWPLAYERID:
......@@ -638,7 +640,25 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
HEAP_ZERO_MEMORY,
*lpdwMsgSize );
FIXME( "Ignoring dwFlags in msg\n" );
FIXME( "Ignoring dwFlags in request msg\n" );
#if 0
/* This is just a test. See how large the SPData is and send it */
{
LPVOID lpData;
DWORD dwDataSize;
HRESULT hr;
hr = IDirectPlaySP_GetSPData( This->dp2->spData.lpISP, &lpData,
&dwDataSize, DPSET_REMOTE );
if( FAILED(hr) )
{
ERR( "Unable to get remote SPData %s\n", DPLAYX_HresultToString(hr) );
}
}
#endif
/* Setup the reply */
lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
......@@ -648,10 +668,10 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
lpReply->envelope.wVersion = DPMSGVER_DP6;
#if 0
/* FIXME: Need to know the proper contents of the message! */
lpReply->dpidNewPlayerId = DP_NextObjectId();
#endif
TRACE( "Allocating new playerid 0x%08lx from remote request\n",
lpReply->dpidNewPlayerId );
break;
}
......@@ -659,8 +679,6 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
case DPMSGCMD_NEWPLAYERIDREPLY:
{
DebugBreak();
if( This->dp2->hMsgReceipt )
{
/* This is a hack only */
......@@ -672,7 +690,7 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
}
else
{
ERR( "No receipt event set\n" );
ERR( "No receipt event set - only expecting in reply mode\n" );
}
break;
......@@ -1304,6 +1322,7 @@ static HRESULT WINAPI DP_IF_CreatePlayer
DWORD dwFlags,
BOOL bAnsi )
{
HANDLE hr = DP_OK;
lpPlayerData lpPData;
lpPlayerList lpPList;
......@@ -1341,7 +1360,7 @@ static HRESULT WINAPI DP_IF_CreatePlayer
}
else
{
HRESULT hr = DP_MSG_SendRequestPlayerId( This, dwFlags, lpidPlayer );
hr = DP_MSG_SendRequestPlayerId( This, dwFlags, lpidPlayer );
if( FAILED(hr) )
{
......@@ -1409,7 +1428,34 @@ static HRESULT WINAPI DP_IF_CreatePlayer
data.lpSPMessageHeader = lpMsgHdr;
data.lpISP = This->dp2->spData.lpISP;
(*This->dp2->spData.lpCB->CreatePlayer)( &data );
hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
}
if( FAILED(hr) )
{
ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
return hr;
}
/* Now let the SP know that this player is a member of the system group */
if( This->dp2->spData.lpCB->AddPlayerToGroup )
{
DPSP_ADDPLAYERTOGROUPDATA data;
data.idPlayer = *lpidPlayer;
data.idGroup = DPID_SYSTEM_GROUP;
data.lpISP = This->dp2->spData.lpISP;
TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
}
if( FAILED(hr) )
{
ERR( "Failed to add player to sys groupwith sp: %s\n",
DPLAYX_HresultToString(hr) );
return hr;
}
/* Inform all other peers of the creation of a new player. If there are
......@@ -1435,11 +1481,11 @@ static HRESULT WINAPI DP_IF_CreatePlayer
/* FIXME: Correct to just use send effectively? */
/* FIXME: Should size include data w/ message or just message "header" */
/* FIXME: Check return code */
DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
0, 0, NULL, NULL, bAnsi );
hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
}
return DP_OK;
return hr;
}
static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
......@@ -1936,6 +1982,9 @@ static void DP_InvokeEnumSessionCallbacks
FIXME( ": not checking for conditions\n" );
/* Not sure if this should be pruning but it's convenient */
NS_PruneSessionCache( lpNSInfo );
NS_ResetSessionEnumeration( lpNSInfo );
/* Enumerate all sessions */
......@@ -2663,7 +2712,7 @@ static HRESULT WINAPI DP_SecureOpen
if( dwFlags & DPOPEN_JOIN )
{
DPID dpidServerId = DPID_SERVERPLAYER;
DPID dpidServerId = DPID_UNKNOWN;
/* Create the server player for this interface. This way we can receive
* messages for this session.
......@@ -2685,6 +2734,12 @@ static HRESULT WINAPI DP_SecureOpen
0, DPPLAYER_SERVERPLAYER, bAnsi );
}
if( FAILED(hr) )
{
ERR( "Couldn't create name server/system player: %s\n",
DPLAYX_HresultToString(hr) );
}
return hr;
}
......
......@@ -18,7 +18,7 @@
/* FIXME: Need to add interface locking inside procedures */
DEFAULT_DEBUG_CHANNEL(dplay);
DEFAULT_DEBUG_CHANNEL(dplay)
/* Prototypes */
static BOOL DPSP_CreateIUnknown( LPVOID lpSP );
......@@ -369,6 +369,8 @@ static HRESULT WINAPI IDirectPlaySPImpl_GetSPPlayerData
FIXME( "(%p)->(0x%08lx,%p,%p,0x%08lx): stub\n",
This, idPlayer, lplpData, lpdwDataSize, dwFlags );
/* What to do in the case where there is nothing set yet? */
*lplpData = This->sp->lpPlayerData;
*lpdwDataSize = This->sp->dwPlayerDataSize;
......@@ -440,6 +442,8 @@ static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
break;
}
case DPMSGCMD_GETNAMETABLE:
case DPMSGCMD_GETNAMETABLEREPLY:
case DPMSGCMD_NEWPLAYERIDREPLY:
case DPMSGCMD_REQUESTNEWPLAYERID:
{
......@@ -796,6 +800,8 @@ static HRESULT WINAPI IDirectPlaySPImpl_GetSPData
}
#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 )
{
......
......@@ -55,23 +55,27 @@ typedef BOOL (CALLBACK* LPENUMMRUCALLBACK)( LPCVOID lpData,
ICOM_DEFINE(IDirectPlaySP,IUnknown)
#undef ICOM_INTERFACE
/* NOTE: The microsoft provided header file doesn't have these access
* functions
*/
/*** 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)
#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)
#define IDirectPlaySP_AddMRUEntry(p,a,b,c,d,e) ICOM_CALL5(AddMRUEntry,p,a,b,c,d,e)
#define IDirectPlaySP_CreateAddress(p,a,b,c,d,e,f) ICOM_CALL6(CreateAddress,p,a,b,c,d,e,f)
#define IDirectPlaySP_EnumAddress(p,a,b,c,d) ICOM_CALL4(EnumAddress,p,a,b,c,d)
#define IDirectPlaySP_EnumMRUEntries(p,a,b,c,d) ICOM_CALL4(EnumMRUEntries,p,a,b,c,d)
#define IDirectPlaySP_GetPlayerFlags(p,a,b) ICOM_CALL2(GetPlayerFlags,p,a,b)
#define IDirectPlaySP_GetSPPlayerData(p,a,b,c,d) ICOM_CALL4(GetSPPlayerData,p,a,b,c,d)
#define IDirectPlaySP_HandleMessage(p,a,b,c) ICOM_CALL3(HandleMessage,p,a,b,c)
#define IDirectPlaySP_SetSPPlayerData(p,a,b,c,d) ICOM_CALL4(SetSPPlayerData,p,a,b,c,d)
#define IDirectPlaySP_CreateCompoundAddress(p,a,b,c,d) ICOM_CALL4(CreateCompoundAddress,p,a,b,c,d)
#define IDirectPlaySP_GetSPData(p,a,b,c) ICOM_CALL3(GetSPData,p,a,b,c)
#define IDirectPlaySP_SetSPData(p,a,b,c) ICOM_CALL3(SetSPData,p,a,b,c)
#define IDirectPlaySP_SendComplete(p,a,b) ICOM_CALL2(SendComplete,p,a,b)
/* SP Callback stuff */
......
......@@ -2,6 +2,7 @@ name dplayx
type win32
init DPLAYX_LibMain
import winmm.dll
import ole32.dll
import advapi32.dll
import kernel32.dll
......@@ -11,7 +12,7 @@ import kernel32.dll
3 stdcall DirectPlayEnumerateW(ptr ptr) DirectPlayEnumerateW
4 stdcall DirectPlayLobbyCreateA(ptr ptr ptr ptr long) DirectPlayLobbyCreateA
5 stdcall DirectPlayLobbyCreateW(ptr ptr ptr ptr long) DirectPlayLobbyCreateW
6 stub gdwDPlaySPRefCount
6 extern gdwDPlaySPRefCount gdwDPlaySPRefCount
9 stdcall DirectPlayEnumerate(ptr ptr) DirectPlayEnumerateA
10 stdcall DllCanUnloadNow() DPLAYX_DllCanUnloadNow
11 stdcall DllGetClassObject(ptr ptr ptr) DPLAYX_DllGetClassObject
......@@ -149,10 +149,6 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
DWORD dwWaitReturn;
HRESULT hr = DP_OK;
FIXME( "semi stub\n" );
DebugBreak();
dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
......@@ -185,6 +181,8 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
/* Setup for receipt */
This->dp2->hMsgReceipt = CreateEventA( NULL, FALSE, FALSE, NULL );
TRACE( "Sending request for player id\n" );
hr = (*This->dp2->spData.lpCB->Send)( &data );
......@@ -192,6 +190,7 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
{
ERR( "Request for new playerID send failed: %s\n",
DPLAYX_HresultToString( hr ) );
return DPERR_NOCONNECTION;
}
}
......@@ -199,13 +198,36 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
if( dwWaitReturn != WAIT_OBJECT_0 )
{
ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
hr = DPERR_TIMEOUT;
}
CloseHandle( This->dp2->hMsgReceipt );
This->dp2->hMsgReceipt = 0;
/* Need to examine the data and extract the new player id */
/* I just hope that dplay doesn't return the whole new player! */
if( !FAILED(hr) )
{
LPCDPMSG_NEWPLAYERIDREPLY lpcReply;
lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)This->dp2->lpMsgReceived;
*lpdpidAllocatedId = lpcReply->dpidNewPlayerId;
TRACE( "Received reply for id = 0x%08lx\n", lpcReply->dpidNewPlayerId );
/* FIXME: I think that the rest of the message has something to do
* with remote data for the player that perhaps I need to setup.
*/
#if 0
/* Set the passed service provider data */
IDirectPlaySP_SetSPData( This->dp2->spData.lpISP, data,
msgsize, DPSET_REMOTE );
#endif
HeapFree( GetProcessHeap(), 0, This->dp2->lpMsgReceived );
This->dp2->lpMsgReceived = NULL;
}
return hr;
}
......
......@@ -19,9 +19,6 @@ DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
#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
......@@ -34,7 +31,9 @@ DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
#define DPMSGCMD_ENUMGROUPS 17
#define DPMSGCMD_FORWARDCREATEPLAYER 19 /* This may be a get name table req */
#define DPMSGCMD_GETNAMETABLE 19
#define DPMSGCMD_GETNAMETABLEREPLY 29
/* This is what DP 6 defines it as. Don't know what it means. All messages
* defined below are DPMSGVER_DP6.
......@@ -48,7 +47,7 @@ DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
* the message.
*/
/* Size is 4 bytes */
/* Size is 8 bytes */
typedef struct tagDPMSG_SENDENVELOPE
{
DWORD dwMagic;
......@@ -126,15 +125,17 @@ typedef struct tagDPMSG_REQUESTNEWPLAYERID
} DPMSG_REQUESTNEWPLAYERID, *LPDPMSG_REQUESTNEWPLAYERID;
typedef const DPMSG_REQUESTNEWPLAYERID* LPCDPMSG_REQUESTNEWPLAYERID;
/* 64 byte - ~18 header ~= 46 bytes msg */
/* 48 bytes msg */
typedef struct tagDPMSG_NEWPLAYERIDREPLY
{
DPMSG_SENDENVELOPE envelope;
#if 0
DPID dpidNewPlayerId;
#else
BYTE unknown[38];
#if 1
/* Assume that this is data that is tacked on to the end of the message
* that comes from the SP remote data stored that needs to be propagated.
*/
BYTE unknown[36]; /* This appears to always be 0 - not sure though */
#endif
} DPMSG_NEWPLAYERIDREPLY, *LPDPMSG_NEWPLAYERIDREPLY;
......
......@@ -77,7 +77,7 @@ do { \
*/
#define DPQ_FIND_ENTRY( head, elm, field, fieldCompareOperator, fieldToCompare, rc )\
do { \
(rc) = (head).lpQHFirst; /* NULL head? */ \
(rc) = DPQ_FIRST(head); /* NULL head? */ \
\
while( rc ) \
{ \
......@@ -98,6 +98,39 @@ do { \
/* head - pointer to DPQ_HEAD struct
* elm - how to find the next element
* field - to be concatenated to rc to compare with fieldToCompare
* fieldToCompare - The value that we're comparing against
* compare_cb - Callback to invoke to determine if comparision should continue.
* Callback must be defined with DPQ_DECL_COMPARECB.
* rc - Variable to put the return code. Same type as (head).lpQHFirst
*/
#define DPQ_FIND_ENTRY_CB( head, elm, field, compare_cb, fieldToCompare, rc )\
do { \
(rc) = DPQ_FIRST(head); /* NULL head? */ \
\
while( rc ) \
{ \
/* What we're searching for? */ \
if( compare_cb( &((rc)->field), &(fieldToCompare) ) ) \
{ \
break; /* no more */ \
} \
\
/* End of list check */ \
if( ( (rc) = (rc)->elm.lpQNext ) == (head).lpQHFirst ) \
{ \
rc = NULL; \
break; \
} \
} \
} while(0)
/* How to define the method to be passed to DPQ_DELETEQ */
#define DPQ_DECL_COMPARECB( name, type ) BOOL name( const type* elem1, const type* elem2 )
/* head - pointer to DPQ_HEAD struct
* elm - how to find the next element
* field - to be concatenated to rc to compare with fieldToEqual
* fieldToCompare - The value that we're comparing against
* fieldCompareOperator - The logical operator to compare field and
......@@ -115,19 +148,42 @@ do { \
} \
} while(0)
/* head - pointer to DPQ_HEAD struct
* elm - how to find the next element
* field - to be concatenated to rc to compare with fieldToCompare
* fieldToCompare - The value that we're comparing against
* compare_cb - Callback to invoke to determine if comparision should continue.
* Callback must be defined with DPQ_DECL_COMPARECB.
* rc - Variable to put the return code. Same type as (head).lpQHFirst
*/
#define DPQ_REMOVE_ENTRY_CB( head, elm, field, compare_cb, fieldToCompare, rc )\
do { \
DPQ_FIND_ENTRY_CB( head, elm, field, compare_cb, fieldToCompare, rc );\
\
/* Was the element found? */ \
if( rc ) \
{ \
DPQ_REMOVE( head, rc, elm ); \
} \
} 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 ); \
}
#define DPQ_DELETEQ( head, field, type, df ) \
do \
{ \
while( !DPQ_IS_EMPTY(head) ) \
{ \
type holder = DPQ_FIRST(head); \
DPQ_REMOVE( head, holder, field ); \
df( holder ); \
} \
} while(0)
/* How to define the method to be passed to DPQ_DELETEQ */
#define DPQ_DECL_DELETECB( name, type ) void name( type elem )
......
......@@ -1137,7 +1137,7 @@ BOOL DPL_CreateAndSetLobbyHandles( DWORD dwDestProcessId, HANDLE hDestProcess,
LPHANDLE lphRead )
{
/* These are the handles for the created process */
HANDLE hAppStart, hAppDeath, hAppRead;
HANDLE hAppStart, hAppDeath, hAppRead, hTemp;
SECURITY_ATTRIBUTES s_attrib;
s_attrib.nLength = sizeof( s_attrib );
......@@ -1145,9 +1145,14 @@ BOOL DPL_CreateAndSetLobbyHandles( DWORD dwDestProcessId, HANDLE hDestProcess,
s_attrib.bInheritHandle = TRUE;
/* FIXME: Is there a handle leak here? */
*lphStart = CreateEventA( &s_attrib, TRUE, FALSE, NULL );
*lphDeath = CreateEventA( &s_attrib, TRUE, FALSE, NULL );
*lphRead = CreateEventA( &s_attrib, TRUE, FALSE, NULL );
hTemp = CreateEventA( &s_attrib, TRUE, FALSE, NULL );
*lphStart = ConvertToGlobalHandle( hTemp );
hTemp = CreateEventA( &s_attrib, TRUE, FALSE, NULL );
*lphDeath = ConvertToGlobalHandle( hTemp );
hTemp = CreateEventA( &s_attrib, TRUE, FALSE, NULL );
*lphRead = ConvertToGlobalHandle( hTemp );
if( ( !DuplicateHandle( GetCurrentProcess(), *lphStart,
hDestProcess, &hAppStart,
......
......@@ -11,6 +11,7 @@
#include "winbase.h"
#include "debugtools.h"
#include "heap.h"
#include "mmsystem.h"
#include "dplayx_global.h"
#include "name_server.h"
......@@ -43,16 +44,25 @@ struct NSCache
};
typedef struct NSCache NSCache, *lpNSCache;
/* Function prototypes */
DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData );
/* Name Server functions
* ---------------------
*/
void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd )
{
#if 0
/* FIXME: Remove this method? */
DPLAYX_SetLocalSession( lpsd );
#endif
}
DPQ_DECL_COMPARECB( cbUglyPig, GUID )
{
return IsEqualGUID( elem1, elem2 );
}
/* Store the given NS remote address for future reference */
void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr,
DWORD dwHdrSize,
......@@ -65,8 +75,21 @@ void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr,
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.
* so we remove the old and add the new so oldest is at front.
*/
/* See if we can find this session. If we can, remove it as it's a dup */
DPQ_REMOVE_ENTRY_CB( lpCache->first, next, data->guidInstance, cbUglyPig,
lpMsg->sd.guidInstance, lpCacheNode );
if( lpCacheNode != NULL )
{
TRACE( "Duplicate session entry for %s removed - updated version kept\n",
debugstr_guid( &lpCacheNode->data->guidInstance ) );
cbDeleteNSNodeFromHeap( lpCacheNode );
}
/* Add this to the list */
lpCacheNode = (lpNSCacheData)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( *lpCacheNode ) );
......@@ -96,7 +119,7 @@ void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr,
HEAP_ZERO_MEMORY,
(LPWSTR)(lpMsg+1) );
lpCacheNode->dwTime = GetTickCount();
lpCacheNode->dwTime = timeGetTime();
DPQ_INSERT(lpCache->first, lpCacheNode, next );
......@@ -116,6 +139,10 @@ LPVOID NS_GetNSAddr( LPVOID lpNSInfo )
/* 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?
* This is going to have to go into dplay somehow. Perhaps it
* comes back with app server id for the join command! Oh...that
* must be it. That would make this method obsolete once that's
* in place.
*/
return lpCache->first.lpQHFirst->lpNSAddrHdr;
......@@ -159,17 +186,17 @@ HRESULT NS_SendSessionRequestBroadcast( LPCGUID lpcGuid,
return (lpSpData->lpCB->EnumSessions)( &data );
}
DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData );
/* Delete a name server node which has been allocated on the heap */
DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData )
{
/* NOTE: This proc doesn't deal with the walking pointer */
/* 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 )
{
......@@ -216,7 +243,6 @@ void NS_DeleteSessionCache( LPVOID lpNSInfo )
/* Reinitialize the present pointer for this cache */
void NS_ResetSessionEnumeration( LPVOID lpNSInfo )
{
((lpNSCache)lpNSInfo)->present = ((lpNSCache)lpNSInfo)->first.lpQHFirst;
}
......@@ -244,33 +270,60 @@ LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo )
/* This method should check to see if there are any sessions which are
* older than the criteria. If so, just delete that information.
*/
/* FIXME: This needs to be called by some periodic timer */
void NS_PruneSessionCache( LPVOID lpNSInfo )
{
lpNSCache lpCache = lpNSInfo;
lpNSCacheData lpCacheEntry;
DWORD dwPresentTime = GetTickCount();
#if defined( HACK_TIMEGETTIME )
DWORD dwPruneTime = dwPresentTime - 2; /* One iteration with safety */
#else
DWORD dwPruneTime = dwPresentTime - 10000 /* 10 secs? */;
#endif
FIXME( ": semi stub\n" );
const DWORD dwPresentTime = timeGetTime();
const DWORD dwPrunePeriod = 60000; /* is 60 secs enough? */
const DWORD dwPruneTime = dwPresentTime - dwPrunePeriod;
/* FIXME: This doesn't handle time roll over correctly */
/* FIXME: Session memory leak on delete */
do
/* This silly little algorithm is based on the fact we keep entries in
* the queue in a time based order. It also assumes that it is not possible
* to wrap around over yourself (which is not unreasonable).
* The if statements verify if the first entry in the queue is less
* than dwPrunePeriod old depending on the "clock" roll over.
*/
for( ;; )
{
DPQ_FIND_ENTRY( lpCache->first, next, dwTime, <=, dwPruneTime, lpCacheEntry );
lpNSCacheData lpFirstData;
if( DPQ_IS_EMPTY(lpCache->first) )
{
/* Nothing to prune */
break;
}
if( dwPruneTime > dwPresentTime ) /* 0 <= dwPresentTime <= dwPrunePeriod */
{
if( ( DPQ_FIRST(lpCache->first)->dwTime <= dwPresentTime ) ||
( DPQ_FIRST(lpCache->first)->dwTime > dwPruneTime )
)
{
/* Less than dwPrunePeriod old - keep */
break;
}
}
else /* dwPrunePeriod <= dwPresentTime <= max dword */
{
if( ( DPQ_FIRST(lpCache->first)->dwTime <= dwPresentTime ) &&
( DPQ_FIRST(lpCache->first)->dwTime > dwPruneTime )
)
{
/* Less than dwPrunePeriod old - keep */
break;
}
}
lpFirstData = DPQ_FIRST(lpCache->first);
DPQ_REMOVE( lpCache->first, DPQ_FIRST(lpCache->first), next );
cbDeleteNSNodeFromHeap( lpFirstData );
}
while( lpCacheEntry != NULL );
}
/* Message stuff */
/* NAME SERVER Message stuff */
void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg,
LPDPSP_REPLYDATA lpReplyData,
IDirectPlay2Impl* lpDP )
......@@ -318,4 +371,3 @@ void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg,
lstrcpyW( (LPWSTR)(rmsg+1), string );
}
......@@ -44,6 +44,12 @@ dplayx_messages.h,
dplayx_messages.c: Messaging interface required for both DirectPlay and
DirectPlayLobby.
dplaysp.c,
dplaysp.h: COM interface between DPLAYX and the service provider dlls. dplaysp.h is
something that should be included into any service provider. Basically
the COM interface is partially documented but is generally lacking in the
finer points.
Presently the architectural relationship between this files is a little shakey, but
isn't so sufficiently bad that it needs fixing yet.
......@@ -56,7 +62,17 @@ However, now that address separation is a reality, all binary samples provided
in the sdk can be used. I have had success spawning processes and one
directx7 example will allow creation of an app and allow another to join it.
Unfortunately, there isn't much for it to be able to do give the state of
inter lobby messaging.
inter directlobby or directplay messaging.
Messages which work:
For session enumeration: DPMSGCMD_ENUMSESSIONSREPLY & DPMSGCMD_ENUMSESSIONSREQUEST
have most fields understood, but not all. Everything _seems_
to work.
For playerid requesting: DPMSGCMD_REQUESTNEWPLAYERID & DPMSGCMD_NEWPLAYERIDREPLY
barely work. This needs to be completed for sessions to be
able to actually start.
A small issue will be the fact that DirectX 6.1(ie. DirectPlay4) introduces a layer of functionality
inside the DP objects which provide guaranteed protocol delivery. This is
......@@ -96,18 +112,21 @@ TODO:
share registry implementation (or at least simplify).
- Add in appropriate RegCloseKey calls for all the opening we're doing...
- Fix all the buffer sizes for registry calls. They're off by one - but in a safe direction.
- Find out how to call the service provider dlls - they don't have a published interface!
- (done) Find out how to call the service provider dlls - they don't have a published interface!
- Fix race condition on interface destruction
- Handles need to be correctly reference counted
- Need to check if we need to deallocate any list objects when destroying
dplay interface
- RunApplication process spawning needs to have correct syncronization.
- Need to get inter lobby messages working.
- Decypher dplay messages between applications and implement...
- Need to implement lobby session spawning.
ENHANCEMENTS:
- Improve footprint and realtime blocking by setting up a seperate data share
between lobby application and client since there can be multiple apps per
client.
client. Also get rid of offset dependency by making data offset independent
somehow.
- Handle everything in UNICODE (as server does) and do conversions for ANSI
interfaces. Should cut down on dplayx code base and maintanability (marginally)
and could be used to improve efficiency of dialog with the server (it wouldn't
......@@ -124,34 +143,23 @@ Programs to make work:
Next API to implement on a per SDK program basis:
override.exe
- fixme:dplay:DirectPlayCreate Modem binding not supported yet
- DirectPlay3AImpl_InitializeConnection
- DirectPlay2AImpl_Open
- ?
- (calls dpserial so basic problems with that remain)
- after that ?
dplaunch.exe
- Just needs final process startup messages to be exchanged correctly!
- I think that everything is basically working. The launched app may not
work on the other hand.
lserver.exe
- IDirectPlayLobby2WImpl_Connect
- fixme:dplay:DirectPlayCreate Modem binding not supported yet
- IDirectPlay3WImpl_CreatePlayer
- IDirectPlay3WImpl_CreateGroup
- IDirectPlay3WImpl_SetGroupData
- IDirectPlay3WImpl_Send
- ?
- Missing messaging portion. Everything else works.
bellhop.exe
- DP_SendSessionRequestBroadcast (implement the name server stuff)
- Need to implement lobby server support.
- ?
dpslots.exe
- IDirectPlayLobby3AImpl_ConnectEx
- ?
override.exe
- DirectPlayCreate Service provider binding not supported yet
- ?
- Works as host except for message stuff
- Missing correct handling of receipt of playerid
Other TODO:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment