- Remove winmm hack in dplay code

- Fix up some missing holes in the code
- More message implementation
- Status documentation update
This commit is contained in:
Peter Hunnisett 2000-09-26 23:11:48 +00:00 committed by Alexandre Julliard
parent a387aa4868
commit 72526ba4f5
12 changed files with 314 additions and 104 deletions

View File

@ -380,7 +380,7 @@ crtdll/libcrtdll.so: libkernel32.so
ddraw/libddraw.so: libole32.so libuser32.so libx11drv.so libgdi32.so libkernel32.so ddraw/libddraw.so: libole32.so libuser32.so libx11drv.so libgdi32.so libkernel32.so
dinput/libdinput.so: libuser32.so libkernel32.so dinput/libdinput.so: libuser32.so libkernel32.so
dplay/libdplay.so: libdplayx.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 dsound/libdsound.so: libwinmm.so libkernel32.so
gdi/libgdi32.so: libkernel32.so gdi/libgdi32.so: libkernel32.so
icmp/libicmp.so: libkernel32.so icmp/libicmp.so: libkernel32.so

View File

@ -4,7 +4,7 @@ SRCDIR = @srcdir@
VPATH = @srcdir@ VPATH = @srcdir@
MODULE = dplayx MODULE = dplayx
SOVERSION = 1.0 SOVERSION = 1.0
IMPORTS = ole32 advapi32 kernel32 IMPORTS = winmm ole32 advapi32 kernel32
C_SRCS = \ C_SRCS = \
dpclassfactory.c \ dpclassfactory.c \

View File

@ -622,6 +622,8 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
This, lpMessageBody, dwMessageBodySize, lpMessageHeader, wCommandId, This, lpMessageBody, dwMessageBodySize, lpMessageHeader, wCommandId,
wVersion ); wVersion );
DebugBreak();
switch( wCommandId ) switch( wCommandId )
{ {
case DPMSGCMD_REQUESTNEWPLAYERID: case DPMSGCMD_REQUESTNEWPLAYERID:
@ -638,7 +640,25 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
HEAP_ZERO_MEMORY, HEAP_ZERO_MEMORY,
*lpdwMsgSize ); *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 */ /* Setup the reply */
lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) + lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
@ -648,10 +668,10 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY; lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
lpReply->envelope.wVersion = DPMSGVER_DP6; lpReply->envelope.wVersion = DPMSGVER_DP6;
#if 0
/* FIXME: Need to know the proper contents of the message! */
lpReply->dpidNewPlayerId = DP_NextObjectId(); lpReply->dpidNewPlayerId = DP_NextObjectId();
#endif
TRACE( "Allocating new playerid 0x%08lx from remote request\n",
lpReply->dpidNewPlayerId );
break; break;
} }
@ -659,8 +679,6 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
case DPMSGCMD_NEWPLAYERIDREPLY: case DPMSGCMD_NEWPLAYERIDREPLY:
{ {
DebugBreak();
if( This->dp2->hMsgReceipt ) if( This->dp2->hMsgReceipt )
{ {
/* This is a hack only */ /* This is a hack only */
@ -672,7 +690,7 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
} }
else else
{ {
ERR( "No receipt event set\n" ); ERR( "No receipt event set - only expecting in reply mode\n" );
} }
break; break;
@ -1304,6 +1322,7 @@ static HRESULT WINAPI DP_IF_CreatePlayer
DWORD dwFlags, DWORD dwFlags,
BOOL bAnsi ) BOOL bAnsi )
{ {
HANDLE hr = DP_OK;
lpPlayerData lpPData; lpPlayerData lpPData;
lpPlayerList lpPList; lpPlayerList lpPList;
@ -1341,7 +1360,7 @@ static HRESULT WINAPI DP_IF_CreatePlayer
} }
else else
{ {
HRESULT hr = DP_MSG_SendRequestPlayerId( This, dwFlags, lpidPlayer ); hr = DP_MSG_SendRequestPlayerId( This, dwFlags, lpidPlayer );
if( FAILED(hr) ) if( FAILED(hr) )
{ {
@ -1409,7 +1428,34 @@ static HRESULT WINAPI DP_IF_CreatePlayer
data.lpSPMessageHeader = lpMsgHdr; data.lpSPMessageHeader = lpMsgHdr;
data.lpISP = This->dp2->spData.lpISP; 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 /* 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: Correct to just use send effectively? */
/* FIXME: Should size include data w/ message or just message "header" */ /* FIXME: Should size include data w/ message or just message "header" */
/* FIXME: Check return code */ /* FIXME: Check return code */
DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
0, 0, NULL, NULL, bAnsi ); sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
} }
return DP_OK; return hr;
} }
static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
@ -1936,6 +1982,9 @@ static void DP_InvokeEnumSessionCallbacks
FIXME( ": not checking for conditions\n" ); FIXME( ": not checking for conditions\n" );
/* Not sure if this should be pruning but it's convenient */
NS_PruneSessionCache( lpNSInfo );
NS_ResetSessionEnumeration( lpNSInfo ); NS_ResetSessionEnumeration( lpNSInfo );
/* Enumerate all sessions */ /* Enumerate all sessions */
@ -2663,7 +2712,7 @@ static HRESULT WINAPI DP_SecureOpen
if( dwFlags & DPOPEN_JOIN ) if( dwFlags & DPOPEN_JOIN )
{ {
DPID dpidServerId = DPID_SERVERPLAYER; DPID dpidServerId = DPID_UNKNOWN;
/* Create the server player for this interface. This way we can receive /* Create the server player for this interface. This way we can receive
* messages for this session. * messages for this session.
@ -2685,6 +2734,12 @@ static HRESULT WINAPI DP_SecureOpen
0, DPPLAYER_SERVERPLAYER, bAnsi ); 0, DPPLAYER_SERVERPLAYER, bAnsi );
} }
if( FAILED(hr) )
{
ERR( "Couldn't create name server/system player: %s\n",
DPLAYX_HresultToString(hr) );
}
return hr; return hr;
} }

View File

@ -18,7 +18,7 @@
/* FIXME: Need to add interface locking inside procedures */ /* FIXME: Need to add interface locking inside procedures */
DEFAULT_DEBUG_CHANNEL(dplay); DEFAULT_DEBUG_CHANNEL(dplay)
/* Prototypes */ /* Prototypes */
static BOOL DPSP_CreateIUnknown( LPVOID lpSP ); 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", FIXME( "(%p)->(0x%08lx,%p,%p,0x%08lx): stub\n",
This, idPlayer, lplpData, lpdwDataSize, dwFlags ); This, idPlayer, lplpData, lpdwDataSize, dwFlags );
/* What to do in the case where there is nothing set yet? */
*lplpData = This->sp->lpPlayerData; *lplpData = This->sp->lpPlayerData;
*lpdwDataSize = This->sp->dwPlayerDataSize; *lpdwDataSize = This->sp->dwPlayerDataSize;
@ -440,6 +442,8 @@ static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
break; break;
} }
case DPMSGCMD_GETNAMETABLE:
case DPMSGCMD_GETNAMETABLEREPLY:
case DPMSGCMD_NEWPLAYERIDREPLY: case DPMSGCMD_NEWPLAYERIDREPLY:
case DPMSGCMD_REQUESTNEWPLAYERID: case DPMSGCMD_REQUESTNEWPLAYERID:
{ {
@ -796,6 +800,8 @@ static HRESULT WINAPI IDirectPlaySPImpl_GetSPData
} }
#endif #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! */ /* Yes, we're supposed to return a pointer to the memory we have stored! */
if( dwFlags == DPSET_REMOTE ) if( dwFlags == DPSET_REMOTE )
{ {

View File

@ -55,23 +55,27 @@ typedef BOOL (CALLBACK* LPENUMMRUCALLBACK)( LPCVOID lpData,
ICOM_DEFINE(IDirectPlaySP,IUnknown) ICOM_DEFINE(IDirectPlaySP,IUnknown)
#undef ICOM_INTERFACE #undef ICOM_INTERFACE
/* NOTE: The microsoft provided header file doesn't have these access
* functions
*/
/*** IUnknown methods ***/ /*** IUnknown methods ***/
#define IDirectPlaySP_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) #define IDirectPlaySP_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b)
#define IDirectPlaySP_AddRef(p) ICOM_CALL (AddRef,p) #define IDirectPlaySP_AddRef(p) ICOM_CALL (AddRef,p)
#define IDirectPlaySP_Release(p) ICOM_CALL (Release,p) #define IDirectPlaySP_Release(p) ICOM_CALL (Release,p)
/*** IDirectPlaySP methods ***/ /*** IDirectPlaySP methods ***/
#define IDirectPlaySP_AddMRUEntry ICOM_CALL5(AddMRUEntry,p,a,b,c,d,e) #define IDirectPlaySP_AddMRUEntry(p,a,b,c,d,e) ICOM_CALL5(AddMRUEntry,p,a,b,c,d,e)
#define IDirectPlaySP_CreateAddress ICOM_CALL6(CreateAddress,p,a,b,c,d,e,f) #define IDirectPlaySP_CreateAddress(p,a,b,c,d,e,f) ICOM_CALL6(CreateAddress,p,a,b,c,d,e,f)
#define IDirectPlaySP_EnumAddress ICOM_CALL4(EnumAddress,p,a,b,c,d) #define IDirectPlaySP_EnumAddress(p,a,b,c,d) ICOM_CALL4(EnumAddress,p,a,b,c,d)
#define IDirectPlaySP_EnumMRUEntries ICOM_CALL4(EnumMRUEntries,p,a,b,c,d) #define IDirectPlaySP_EnumMRUEntries(p,a,b,c,d) ICOM_CALL4(EnumMRUEntries,p,a,b,c,d)
#define IDirectPlaySP_GetPlayerFlags ICOM_CALL2(GetPlayerFlags,p,a,b) #define IDirectPlaySP_GetPlayerFlags(p,a,b) ICOM_CALL2(GetPlayerFlags,p,a,b)
#define IDirectPlaySP_GetSPPlayerData ICOM_CALL4(GetSPPlayerData,p,a,b,c,d) #define IDirectPlaySP_GetSPPlayerData(p,a,b,c,d) ICOM_CALL4(GetSPPlayerData,p,a,b,c,d)
#define IDirectPlaySP_HandleMessage ICOM_CALL3(HandleMessage,p,a,b,c) #define IDirectPlaySP_HandleMessage(p,a,b,c) ICOM_CALL3(HandleMessage,p,a,b,c)
#define IDirectPlaySP_SetSPPlayerData ICOM_CALL4(SetSPPlayerData,p,a,b,c,d) #define IDirectPlaySP_SetSPPlayerData(p,a,b,c,d) ICOM_CALL4(SetSPPlayerData,p,a,b,c,d)
#define IDirectPlaySP_CreateCompoundAddress ICOM_CALL4(CreateCompoundAddress,p,a,b,c,d) #define IDirectPlaySP_CreateCompoundAddress(p,a,b,c,d) ICOM_CALL4(CreateCompoundAddress,p,a,b,c,d)
#define IDirectPlaySP_GetSPData ICOM_CALL3(GetSPData,p,a,b,c) #define IDirectPlaySP_GetSPData(p,a,b,c) ICOM_CALL3(GetSPData,p,a,b,c)
#define IDirectPlaySP_SetSPData ICOM_CALL3(SetSPData,p,a,b,c) #define IDirectPlaySP_SetSPData(p,a,b,c) ICOM_CALL3(SetSPData,p,a,b,c)
#define IDirectPlaySP_SendComplete ICOM_CALL2(SendComplete,p,a,b) #define IDirectPlaySP_SendComplete(p,a,b) ICOM_CALL2(SendComplete,p,a,b)
/* SP Callback stuff */ /* SP Callback stuff */

View File

@ -2,6 +2,7 @@ name dplayx
type win32 type win32
init DPLAYX_LibMain init DPLAYX_LibMain
import winmm.dll
import ole32.dll import ole32.dll
import advapi32.dll import advapi32.dll
import kernel32.dll import kernel32.dll
@ -11,7 +12,7 @@ import kernel32.dll
3 stdcall DirectPlayEnumerateW(ptr ptr) DirectPlayEnumerateW 3 stdcall DirectPlayEnumerateW(ptr ptr) DirectPlayEnumerateW
4 stdcall DirectPlayLobbyCreateA(ptr ptr ptr ptr long) DirectPlayLobbyCreateA 4 stdcall DirectPlayLobbyCreateA(ptr ptr ptr ptr long) DirectPlayLobbyCreateA
5 stdcall DirectPlayLobbyCreateW(ptr ptr ptr ptr long) DirectPlayLobbyCreateW 5 stdcall DirectPlayLobbyCreateW(ptr ptr ptr ptr long) DirectPlayLobbyCreateW
6 stub gdwDPlaySPRefCount 6 extern gdwDPlaySPRefCount gdwDPlaySPRefCount
9 stdcall DirectPlayEnumerate(ptr ptr) DirectPlayEnumerateA 9 stdcall DirectPlayEnumerate(ptr ptr) DirectPlayEnumerateA
10 stdcall DllCanUnloadNow() DPLAYX_DllCanUnloadNow 10 stdcall DllCanUnloadNow() DPLAYX_DllCanUnloadNow
11 stdcall DllGetClassObject(ptr ptr ptr) DPLAYX_DllGetClassObject 11 stdcall DllGetClassObject(ptr ptr ptr) DPLAYX_DllGetClassObject

View File

@ -149,10 +149,6 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
DWORD dwWaitReturn; DWORD dwWaitReturn;
HRESULT hr = DP_OK; HRESULT hr = DP_OK;
FIXME( "semi stub\n" );
DebugBreak();
dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody ); dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize ); lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
@ -185,6 +181,8 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
/* Setup for receipt */ /* Setup for receipt */
This->dp2->hMsgReceipt = CreateEventA( NULL, FALSE, FALSE, NULL ); This->dp2->hMsgReceipt = CreateEventA( NULL, FALSE, FALSE, NULL );
TRACE( "Sending request for player id\n" );
hr = (*This->dp2->spData.lpCB->Send)( &data ); 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", ERR( "Request for new playerID send failed: %s\n",
DPLAYX_HresultToString( hr ) ); DPLAYX_HresultToString( hr ) );
return DPERR_NOCONNECTION;
} }
} }
@ -199,13 +198,36 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
if( dwWaitReturn != WAIT_OBJECT_0 ) if( dwWaitReturn != WAIT_OBJECT_0 )
{ {
ERR( "Wait failed 0x%08lx\n", dwWaitReturn ); ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
hr = DPERR_TIMEOUT;
} }
CloseHandle( This->dp2->hMsgReceipt ); CloseHandle( This->dp2->hMsgReceipt );
This->dp2->hMsgReceipt = 0; This->dp2->hMsgReceipt = 0;
/* Need to examine the data and extract the new player id */ /* 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; return hr;
} }

View File

@ -19,9 +19,6 @@ DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
#define DPMSGCMD_ENUMSESSIONSREPLY 1 #define DPMSGCMD_ENUMSESSIONSREPLY 1
#define DPMSGCMD_ENUMSESSIONSREQUEST 2 #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_REQUESTNEWPLAYERID 5
@ -34,7 +31,9 @@ DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
#define DPMSGCMD_ENUMGROUPS 17 #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 /* This is what DP 6 defines it as. Don't know what it means. All messages
* defined below are DPMSGVER_DP6. * defined below are DPMSGVER_DP6.
@ -48,7 +47,7 @@ DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
* the message. * the message.
*/ */
/* Size is 4 bytes */ /* Size is 8 bytes */
typedef struct tagDPMSG_SENDENVELOPE typedef struct tagDPMSG_SENDENVELOPE
{ {
DWORD dwMagic; DWORD dwMagic;
@ -126,15 +125,17 @@ typedef struct tagDPMSG_REQUESTNEWPLAYERID
} DPMSG_REQUESTNEWPLAYERID, *LPDPMSG_REQUESTNEWPLAYERID; } DPMSG_REQUESTNEWPLAYERID, *LPDPMSG_REQUESTNEWPLAYERID;
typedef const DPMSG_REQUESTNEWPLAYERID* LPCDPMSG_REQUESTNEWPLAYERID; typedef const DPMSG_REQUESTNEWPLAYERID* LPCDPMSG_REQUESTNEWPLAYERID;
/* 64 byte - ~18 header ~= 46 bytes msg */ /* 48 bytes msg */
typedef struct tagDPMSG_NEWPLAYERIDREPLY typedef struct tagDPMSG_NEWPLAYERIDREPLY
{ {
DPMSG_SENDENVELOPE envelope; DPMSG_SENDENVELOPE envelope;
#if 0
DPID dpidNewPlayerId; DPID dpidNewPlayerId;
#else #if 1
BYTE unknown[38]; /* 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 #endif
} DPMSG_NEWPLAYERIDREPLY, *LPDPMSG_NEWPLAYERIDREPLY; } DPMSG_NEWPLAYERIDREPLY, *LPDPMSG_NEWPLAYERIDREPLY;

View File

@ -77,7 +77,7 @@ do { \
*/ */
#define DPQ_FIND_ENTRY( head, elm, field, fieldCompareOperator, fieldToCompare, rc )\ #define DPQ_FIND_ENTRY( head, elm, field, fieldCompareOperator, fieldToCompare, rc )\
do { \ do { \
(rc) = (head).lpQHFirst; /* NULL head? */ \ (rc) = DPQ_FIRST(head); /* NULL head? */ \
\ \
while( rc ) \ while( rc ) \
{ \ { \
@ -96,6 +96,39 @@ do { \
} \ } \
} while(0) } 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_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 /* 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
@ -115,19 +148,42 @@ do { \
} \ } \
} while(0) } 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 /* Delete the entire queue
* head - pointer to the head of the queue * head - pointer to the head of the queue
* field - field to access the next elements of the queue * field - field to access the next elements of the queue
* type - type of the pointer to the element element * type - type of the pointer to the element element
* df - a delete function to be called. Declared with DPQ_DECL_DELETECB. * df - a delete function to be called. Declared with DPQ_DECL_DELETECB.
*/ */
#define DPQ_DELETEQ( head, field, type, df ) \ #define DPQ_DELETEQ( head, field, type, df ) \
while( !DPQ_IS_EMPTY(head) ) \ do \
{ \ { \
type holder = (head).lpQHFirst; \ while( !DPQ_IS_EMPTY(head) ) \
DPQ_REMOVE( head, holder, field ); \ { \
df( holder ); \ 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 */ /* How to define the method to be passed to DPQ_DELETEQ */
#define DPQ_DECL_DELETECB( name, type ) void name( type elem ) #define DPQ_DECL_DELETECB( name, type ) void name( type elem )

View File

@ -1137,7 +1137,7 @@ BOOL DPL_CreateAndSetLobbyHandles( DWORD dwDestProcessId, HANDLE hDestProcess,
LPHANDLE lphRead ) LPHANDLE lphRead )
{ {
/* These are the handles for the created process */ /* These are the handles for the created process */
HANDLE hAppStart, hAppDeath, hAppRead; HANDLE hAppStart, hAppDeath, hAppRead, hTemp;
SECURITY_ATTRIBUTES s_attrib; SECURITY_ATTRIBUTES s_attrib;
s_attrib.nLength = sizeof( s_attrib ); s_attrib.nLength = sizeof( s_attrib );
@ -1145,9 +1145,14 @@ BOOL DPL_CreateAndSetLobbyHandles( DWORD dwDestProcessId, HANDLE hDestProcess,
s_attrib.bInheritHandle = TRUE; s_attrib.bInheritHandle = TRUE;
/* FIXME: Is there a handle leak here? */ /* FIXME: Is there a handle leak here? */
*lphStart = CreateEventA( &s_attrib, TRUE, FALSE, NULL ); hTemp = CreateEventA( &s_attrib, TRUE, FALSE, NULL );
*lphDeath = CreateEventA( &s_attrib, TRUE, FALSE, NULL ); *lphStart = ConvertToGlobalHandle( hTemp );
*lphRead = CreateEventA( &s_attrib, TRUE, FALSE, NULL );
hTemp = CreateEventA( &s_attrib, TRUE, FALSE, NULL );
*lphDeath = ConvertToGlobalHandle( hTemp );
hTemp = CreateEventA( &s_attrib, TRUE, FALSE, NULL );
*lphRead = ConvertToGlobalHandle( hTemp );
if( ( !DuplicateHandle( GetCurrentProcess(), *lphStart, if( ( !DuplicateHandle( GetCurrentProcess(), *lphStart,
hDestProcess, &hAppStart, hDestProcess, &hAppStart,

View File

@ -11,6 +11,7 @@
#include "winbase.h" #include "winbase.h"
#include "debugtools.h" #include "debugtools.h"
#include "heap.h" #include "heap.h"
#include "mmsystem.h"
#include "dplayx_global.h" #include "dplayx_global.h"
#include "name_server.h" #include "name_server.h"
@ -43,16 +44,25 @@ struct NSCache
}; };
typedef struct NSCache NSCache, *lpNSCache; typedef struct NSCache NSCache, *lpNSCache;
/* Function prototypes */
DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData );
/* Name Server functions /* Name Server functions
* --------------------- * ---------------------
*/ */
void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd ) void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd )
{ {
#if 0 #if 0
/* FIXME: Remove this method? */
DPLAYX_SetLocalSession( lpsd ); DPLAYX_SetLocalSession( lpsd );
#endif #endif
} }
DPQ_DECL_COMPARECB( cbUglyPig, GUID )
{
return IsEqualGUID( elem1, elem2 );
}
/* Store the given NS remote address for future reference */ /* Store the given NS remote address for future reference */
void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr, void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr,
DWORD dwHdrSize, DWORD dwHdrSize,
@ -65,8 +75,21 @@ void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr,
TRACE( "%p, %p, %p\n", lpNSAddrHdr, lpMsg, lpNSInfo ); TRACE( "%p, %p, %p\n", lpNSAddrHdr, lpMsg, lpNSInfo );
/* FIXME: Should check to see if the reply is for an existing session. If /* 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, lpCacheNode = (lpNSCacheData)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( *lpCacheNode ) ); sizeof( *lpCacheNode ) );
@ -96,7 +119,7 @@ void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr,
HEAP_ZERO_MEMORY, HEAP_ZERO_MEMORY,
(LPWSTR)(lpMsg+1) ); (LPWSTR)(lpMsg+1) );
lpCacheNode->dwTime = GetTickCount(); lpCacheNode->dwTime = timeGetTime();
DPQ_INSERT(lpCache->first, lpCacheNode, next ); 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. /* 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? * 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; return lpCache->first.lpQHFirst->lpNSAddrHdr;
@ -159,17 +186,17 @@ HRESULT NS_SendSessionRequestBroadcast( LPCGUID lpcGuid,
return (lpSpData->lpCB->EnumSessions)( &data ); 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 ) DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData )
{ {
/* NOTE: This proc doesn't deal with the walking pointer */
/* FIXME: Memory leak on data (contained ptrs) */ /* FIXME: Memory leak on data (contained ptrs) */
HeapFree( GetProcessHeap(), 0, elem->data ); HeapFree( GetProcessHeap(), 0, elem->data );
HeapFree( GetProcessHeap(), 0, elem->lpNSAddrHdr ); HeapFree( GetProcessHeap(), 0, elem->lpNSAddrHdr );
HeapFree( GetProcessHeap(), 0, elem ); HeapFree( GetProcessHeap(), 0, elem );
} }
/* Render all data in a session cache invalid */ /* Render all data in a session cache invalid */
void NS_InvalidateSessionCache( LPVOID lpNSInfo ) void NS_InvalidateSessionCache( LPVOID lpNSInfo )
{ {
@ -216,7 +243,6 @@ void NS_DeleteSessionCache( LPVOID lpNSInfo )
/* Reinitialize the present pointer for this cache */ /* Reinitialize the present pointer for this cache */
void NS_ResetSessionEnumeration( LPVOID lpNSInfo ) void NS_ResetSessionEnumeration( LPVOID lpNSInfo )
{ {
((lpNSCache)lpNSInfo)->present = ((lpNSCache)lpNSInfo)->first.lpQHFirst; ((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 /* This method should check to see if there are any sessions which are
* older than the criteria. If so, just delete that information. * 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 ) void NS_PruneSessionCache( LPVOID lpNSInfo )
{ {
lpNSCache lpCache = lpNSInfo; lpNSCache lpCache = lpNSInfo;
lpNSCacheData lpCacheEntry;
DWORD dwPresentTime = GetTickCount(); const DWORD dwPresentTime = timeGetTime();
#if defined( HACK_TIMEGETTIME ) const DWORD dwPrunePeriod = 60000; /* is 60 secs enough? */
DWORD dwPruneTime = dwPresentTime - 2; /* One iteration with safety */ const DWORD dwPruneTime = dwPresentTime - dwPrunePeriod;
#else
DWORD dwPruneTime = dwPresentTime - 10000 /* 10 secs? */;
#endif
FIXME( ": semi stub\n" ); /* 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
/* FIXME: This doesn't handle time roll over correctly */ * to wrap around over yourself (which is not unreasonable).
/* FIXME: Session memory leak on delete */ * The if statements verify if the first entry in the queue is less
do * 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 );
} }
/* NAME SERVER Message stuff */
/* Message stuff */
void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg, void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg,
LPDPSP_REPLYDATA lpReplyData, LPDPSP_REPLYDATA lpReplyData,
IDirectPlay2Impl* lpDP ) IDirectPlay2Impl* lpDP )
@ -318,4 +371,3 @@ void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg,
lstrcpyW( (LPWSTR)(rmsg+1), string ); lstrcpyW( (LPWSTR)(rmsg+1), string );
} }

View File

@ -44,6 +44,12 @@ dplayx_messages.h,
dplayx_messages.c: Messaging interface required for both DirectPlay and dplayx_messages.c: Messaging interface required for both DirectPlay and
DirectPlayLobby. 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 Presently the architectural relationship between this files is a little shakey, but
isn't so sufficiently bad that it needs fixing yet. 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 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. 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 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 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 inside the DP objects which provide guaranteed protocol delivery. This is
@ -96,18 +112,21 @@ TODO:
share registry implementation (or at least simplify). share registry implementation (or at least simplify).
- Add in appropriate RegCloseKey calls for all the opening we're doing... - 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. - 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 - Fix race condition on interface destruction
- Handles need to be correctly reference counted - Handles need to be correctly reference counted
- Need to check if we need to deallocate any list objects when destroying - Need to check if we need to deallocate any list objects when destroying
dplay interface dplay interface
- RunApplication process spawning needs to have correct syncronization. - RunApplication process spawning needs to have correct syncronization.
- Need to get inter lobby messages working. - Need to get inter lobby messages working.
- Decypher dplay messages between applications and implement...
- Need to implement lobby session spawning.
ENHANCEMENTS: ENHANCEMENTS:
- Improve footprint and realtime blocking by setting up a seperate data share - Improve footprint and realtime blocking by setting up a seperate data share
between lobby application and client since there can be multiple apps per 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 - Handle everything in UNICODE (as server does) and do conversions for ANSI
interfaces. Should cut down on dplayx code base and maintanability (marginally) 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 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: Next API to implement on a per SDK program basis:
override.exe override.exe
- fixme:dplay:DirectPlayCreate Modem binding not supported yet - (calls dpserial so basic problems with that remain)
- DirectPlay3AImpl_InitializeConnection - after that ?
- DirectPlay2AImpl_Open
- ?
dplaunch.exe 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 lserver.exe
- IDirectPlayLobby2WImpl_Connect - Missing messaging portion. Everything else works.
- fixme:dplay:DirectPlayCreate Modem binding not supported yet
- IDirectPlay3WImpl_CreatePlayer
- IDirectPlay3WImpl_CreateGroup
- IDirectPlay3WImpl_SetGroupData
- IDirectPlay3WImpl_Send
- ?
bellhop.exe bellhop.exe
- DP_SendSessionRequestBroadcast (implement the name server stuff) - Need to implement lobby server support.
- ? - ?
dpslots.exe dpslots.exe
- IDirectPlayLobby3AImpl_ConnectEx - Works as host except for message stuff
- ? - Missing correct handling of receipt of playerid
override.exe
- DirectPlayCreate Service provider binding not supported yet
- ?
Other TODO: Other TODO: