mirror of
git://source.winehq.org/git/wine.git
synced 2024-08-31 02:24:08 +00:00
- 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:
parent
a387aa4868
commit
72526ba4f5
|
@ -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 ) \
|
||||
{ \
|
||||
|
@ -96,6 +96,39 @@ 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_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
|
||||
|
@ -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
|
||||
const DWORD dwPresentTime = timeGetTime();
|
||||
const DWORD dwPrunePeriod = 60000; /* is 60 secs enough? */
|
||||
const DWORD dwPruneTime = dwPresentTime - dwPrunePeriod;
|
||||
|
||||
FIXME( ": semi stub\n" );
|
||||
|
||||
/* 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:
|
||||
|
||||
|
|
Loading…
Reference in a new issue