From ef6dca5c37d7fe945d3c452cdd5c7dba227193ae Mon Sep 17 00:00:00 2001 From: Peter Hunnisett Date: Fri, 25 Aug 2000 21:58:05 +0000 Subject: [PATCH] - Implemented loading and initialization of service providers - Created service provider COM object - Lots of dplay/dplobby implementation/fixes - Clean up of ole/guid.c --- dlls/dplayx/Makefile.in | 1 + dlls/dplayx/dpclassfactory.c | 16 +- dlls/dplayx/dpinit.h | 9 +- dlls/dplayx/dplay.c | 3321 +++++++++++++++++++++++---------- dlls/dplayx/dplay_global.h | 185 ++ dlls/dplayx/dplaysp.c | 880 +++++++++ dlls/dplayx/dplaysp.h | 337 ++++ dlls/dplayx/dplayx_global.c | 272 ++- dlls/dplayx/dplayx_global.h | 25 +- dlls/dplayx/dplayx_main.c | 30 +- dlls/dplayx/dplayx_messages.c | 118 +- dlls/dplayx/dplayx_messages.h | 132 +- dlls/dplayx/dplayx_queue.h | 54 +- dlls/dplayx/dplobby.c | 837 ++++----- dlls/dplayx/name_server.c | 288 ++- dlls/dplayx/name_server.h | 21 +- include/dplay.h | 21 +- ole/Makefile.in | 1 - ole/guid.c | 32 - 19 files changed, 4909 insertions(+), 1671 deletions(-) create mode 100644 dlls/dplayx/dplay_global.h create mode 100644 dlls/dplayx/dplaysp.c create mode 100644 dlls/dplayx/dplaysp.h delete mode 100644 ole/guid.c diff --git a/dlls/dplayx/Makefile.in b/dlls/dplayx/Makefile.in index 83a001d154a..d95b19940e1 100644 --- a/dlls/dplayx/Makefile.in +++ b/dlls/dplayx/Makefile.in @@ -9,6 +9,7 @@ IMPORTS = ole32 advapi32 kernel32 C_SRCS = \ dpclassfactory.c \ dplay.c \ + dplaysp.c \ dplayx_global.c \ dplayx_main.c \ dplayx_messages.c \ diff --git a/dlls/dplayx/dpclassfactory.c b/dlls/dplayx/dpclassfactory.c index 70b7f1372ab..660aa3aec50 100644 --- a/dlls/dplayx/dpclassfactory.c +++ b/dlls/dplayx/dpclassfactory.c @@ -39,7 +39,6 @@ static ULONG WINAPI DP_and_DPL_Release(LPCLASSFACTORY iface) { return --(This->ref); } -/* Not the most efficient implementation, but it's simple */ static HRESULT WINAPI DP_and_DPL_CreateInstance( LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj ) { @@ -47,12 +46,11 @@ static HRESULT WINAPI DP_and_DPL_CreateInstance( TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); - /* FIXME: reuse already created DP/DPL object if present? */ - if ( directPlayLobby_QueryInterface( riid, ppobj ) == S_OK ) + if ( DPL_CreateInterface( riid, ppobj ) == S_OK ) { return S_OK; } - else if ( directPlay_QueryInterface( riid, ppobj ) == S_OK ) + else if ( DP_CreateInterface( riid, ppobj ) == S_OK ) { return S_OK; } @@ -110,13 +108,3 @@ DWORD WINAPI DPLAYX_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv) ERR("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); return CLASS_E_CLASSNOTAVAILABLE; } - -/*********************************************************************** - * DllCanUnloadNow (DPLAYX.@) - */ -HRESULT WINAPI DPLAYX_DllCanUnloadNow(void) -{ - FIXME("(void): stub\n"); - - return S_FALSE; -} diff --git a/dlls/dplayx/dpinit.h b/dlls/dplayx/dpinit.h index 8408765576d..fceecc3e18c 100644 --- a/dlls/dplayx/dpinit.h +++ b/dlls/dplayx/dpinit.h @@ -2,7 +2,12 @@ #ifndef __WINE_DPINIT_H #define __WINE_DPINIT_H -extern HRESULT directPlay_QueryInterface( REFIID riid, LPVOID* ppvObj ); -extern HRESULT directPlayLobby_QueryInterface( REFIID riid, LPVOID* ppvObj ); +#include "wtypes.h" +#include "dplay_global.h" + +extern HRESULT DP_CreateInterface( REFIID riid, LPVOID* ppvObj ); +extern HRESULT DPL_CreateInterface( REFIID riid, LPVOID* ppvObj ); +extern HRESULT DPSP_CreateInterface( REFIID riid, LPVOID* ppvObj, + IDirectPlay2Impl* dp ); #endif diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c index 68c277067ca..7f9ccf03d1d 100644 --- a/dlls/dplayx/dplay.c +++ b/dlls/dplayx/dplay.c @@ -5,8 +5,7 @@ * * */ -#include - +#include "windef.h" #include "winerror.h" #include "winbase.h" #include "winnt.h" @@ -19,180 +18,37 @@ #include "dplayx_global.h" #include "name_server.h" #include "dplayx_queue.h" +#include "dplaysp.h" +#include "dplay_global.h" DEFAULT_DEBUG_CHANNEL(dplay) +/* FIXME: Should this be externed? */ +extern HRESULT DPL_CreateCompoundAddress +( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount, + LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface ); -/* FIXME: This stuff shouldn't really be here. It indicates a poor architectural coupling */ -#include "dplobby.h" -extern HRESULT DPL_CreateCompoundAddress ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount, - LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface ); - - -/***************************************************************************** - * Predeclare the interface implementation structures - */ -typedef struct IDirectPlay2Impl IDirectPlay2AImpl; -typedef struct IDirectPlay2Impl IDirectPlay2Impl; -typedef struct IDirectPlay3Impl IDirectPlay3AImpl; -typedef struct IDirectPlay3Impl IDirectPlay3Impl; -typedef struct IDirectPlay4Impl IDirectPlay4AImpl; -typedef struct IDirectPlay4Impl IDirectPlay4Impl; - -/***************************************************************************** - * IDirectPlay implementation structure - * - * The philosophy behind this extra pointer dereference is that I wanted to - * have the same structure for all types of objects without having to do - * alot of casting. I also only wanted to implement an interface in the - * object it was "released" with IUnknown interface being implemented in the 1 version. - * Of course, with these new interfaces comes the data required to keep the state required - * by these interfaces. So, basically, the pointers contain the data associated with - * a release. If you use the data associated with release 3 in a release 2 object, you'll - * get a run time trap, as that won't have any data. - * - */ -typedef struct tagDirectPlayIUnknownData -{ - DWORD ref; - CRITICAL_SECTION DP_lock; -} DirectPlayIUnknownData; - -typedef struct tagEnumSessionAsyncCallbackData -{ - LPDPENUMSESSIONSCALLBACK2 cb; - LPVOID lpContext; - DWORD dwTimeout; -} EnumSessionAsyncCallbackData; - - -struct PlayerData -{ - /* Individual player information */ - DPID dpid; - - DPNAME name; - HANDLE hEvent; - LPVOID lpData; - DWORD dwDataSize; -}; -typedef struct PlayerData* lpPlayerData; - -struct PlayerList -{ - DPQ_ENTRY(PlayerList) players; - - lpPlayerData lpPData; -}; -typedef struct PlayerList* lpPlayerList; - -struct GroupData -{ - /* Internal information */ - struct GroupData* parent; /* If parent == NULL it's a top level group */ - - DPQ_HEAD(GroupList) groups; /* A group has [0..n] groups */ - DPQ_HEAD(PlayerList) players; /* A group has [0..n] players */ - - DPID idGroupOwner; /* ID of player who owns the group */ - - /* Individual group information exposed to outside */ - DPID dpid; - DPNAME name; - LPVOID lpData; - DWORD dwDataSize; -}; -typedef struct GroupData* lpGroupData; - -struct GroupList -{ - DPQ_ENTRY(GroupList) groups; - - lpGroupData lpGData; -}; -typedef struct GroupList* lpGroupList; - -/* Contains all dp1 and dp2 data members */ -typedef struct tagDirectPlay2Data -{ - BOOL bConnectionOpen; - - HANDLE hEnumSessionThread; - - EnumSessionAsyncCallbackData enumSessionAsyncCallbackData; - - LPVOID lpNameServerData; /* DPlay interface doesn't know contents */ - - BOOL bHostInterface; /* Did this interface create the session */ - - DPQ_HEAD(PlayerList) players; /* All players w/ interface */ - DPQ_HEAD(GroupList) groups; /* All main groups w/ interface */ -} DirectPlay2Data; - -typedef struct tagDirectPlay3Data -{ - BOOL bConnectionInitialized; -} DirectPlay3Data; - -typedef struct tagDirectPlay4Data -{ - BOOL dummy; -} DirectPlay4Data; - -#define DP_IMPL_FIELDS \ - DirectPlayIUnknownData* unk; \ - DirectPlay2Data* dp2; \ - DirectPlay3Data* dp3; \ - DirectPlay4Data* dp4; - -struct IDirectPlay2Impl -{ - ICOM_VFIELD(IDirectPlay2); - DP_IMPL_FIELDS -}; - -struct IDirectPlay3Impl -{ - ICOM_VFIELD(IDirectPlay3); - DP_IMPL_FIELDS -}; - -struct IDirectPlay4Impl -{ - ICOM_VFIELD(IDirectPlay4); - DP_IMPL_FIELDS -}; - -/* Forward declarations of virtual tables */ -static ICOM_VTABLE(IDirectPlay2) directPlay2AVT; -static ICOM_VTABLE(IDirectPlay3) directPlay3AVT; -static ICOM_VTABLE(IDirectPlay4) directPlay4AVT; - -static ICOM_VTABLE(IDirectPlay2) directPlay2WVT; -static ICOM_VTABLE(IDirectPlay3) directPlay3WVT; -static ICOM_VTABLE(IDirectPlay4) directPlay4WVT; /* Local function prototypes */ static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid ); static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid, - LPDPNAME lpName, HANDLE hEvent, - BOOL bAnsi ); + LPDPNAME lpName, DWORD dwFlags, + HANDLE hEvent, BOOL bAnsi ); static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi ); -static void DP_SetPlayerData( lpPlayerData lpPData, LPVOID lpData, - DWORD dwDataSize ); +static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize ); -static lpGroupList DP_FindTopGroup( IDirectPlay2AImpl* This, DPID dpid ); static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, LPDPID lpid, - LPDPNAME lpName, lpGroupData lpParentData, - BOOL bAnsi ); -static void DP_SetGroupData( lpGroupData lpGData, LPVOID lpData, - DWORD dwDataSize ); + LPDPNAME lpName, DWORD dwFlags, + DPID idParent, BOOL bAnsi ); +static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize ); static void DP_DeleteDPNameStruct( LPDPNAME lpDPName ); static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid ); static BOOL cbDeletePlayerFromAllGroups( DPID dpId, DWORD dwPlayerType, LPCDPNAME lpName, DWORD dwFlags, LPVOID lpContext ); -static lpGroupList DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid ); +static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid ); static BOOL cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType, LPCDPNAME lpName, DWORD dwFlags, LPVOID lpContext ); @@ -200,15 +56,16 @@ static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid ); /* Helper methods for player/group interfaces */ static HRESULT WINAPI DP_IF_DeletePlayerFromGroup - ( IDirectPlay2Impl* This, DPID idGroup, DPID idPlayer, BOOL bAnsi ); + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, + DPID idPlayer, BOOL bAnsi ); static HRESULT WINAPI DP_IF_CreatePlayer - ( IDirectPlay2Impl* This, LPDPID lpidPlayer, LPDPNAME lpPlayerName, - HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, - DWORD dwFlags, BOOL bAnsi ); + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer, + LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData, + DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi ); static HRESULT WINAPI DP_IF_DestroyGroup - ( IDirectPlay2Impl* This, DPID idGroup, BOOL bAnsi ); + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi ); static HRESULT WINAPI DP_IF_DestroyPlayer - ( IDirectPlay2Impl* This, DPID idPlayer, BOOL bAnsi ); + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi ); static HRESULT WINAPI DP_IF_EnumGroupPlayers ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, @@ -244,28 +101,88 @@ static HRESULT WINAPI DP_IF_SetPlayerName DWORD dwFlags, BOOL bAnsi ); static HRESULT WINAPI DP_IF_AddGroupToGroup ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup ); +static HRESULT WINAPI DP_IF_CreateGroup + ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup, + LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, + DWORD dwFlags, BOOL bAnsi ); static HRESULT WINAPI DP_IF_CreateGroupInGroup - ( IDirectPlay3Impl* This, DPID idParentGroup, LPDPID lpidGroup, - LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, - DWORD dwFlags ); + ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup, + LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData, + DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_AddPlayerToGroup + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, + DPID idPlayer, BOOL bAnsi ); static HRESULT WINAPI DP_IF_DeleteGroupFromGroup ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup ); - - +static HRESULT WINAPI DP_SetSessionDesc + ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc, + DWORD dwFlags, BOOL bInitial, BOOL bAnsi ); static HRESULT WINAPI DP_SecureOpen ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags, - LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials ); + LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials, + BOOL bAnsi ); +static HRESULT WINAPI DP_SendEx + ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout, + LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_Receive + ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo, + DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_GetMessageQueue + ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags, + LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi ); +static HRESULT WINAPI DP_SP_SendEx + ( IDirectPlay2Impl* This, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout, + LPVOID lpContext, LPDWORD lpdwMsgID ); +static HRESULT WINAPI DP_IF_SetGroupData + ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, + DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_GetPlayerCaps + ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps, + DWORD dwFlags ); +static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_CancelMessage + ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags, + DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_EnumGroupsInGroup + ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_GetGroupParent + ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup, + BOOL bAnsi ); + + +static inline DPID DP_NextObjectId(void); + +static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc, + LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi ); + + +static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData ); +#define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */ +#define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported + we don't have to change much */ +#define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */ + +/* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */ +#define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN ) + +/* Strip out all dwFlags values for CREATEPLAYER msg */ +#define DPMSG_CREATEPLAYER_DWFLAGS(x) 0 + static DWORD kludgePlayerGroupId = 1000; /* ------------------------------------------------------------------ */ -BOOL DP_CreateIUnknown( LPVOID lpDP ) +static BOOL DP_CreateIUnknown( LPVOID lpDP ) { ICOM_THIS(IDirectPlay2AImpl,lpDP); @@ -278,12 +195,10 @@ BOOL DP_CreateIUnknown( LPVOID lpDP ) InitializeCriticalSection( &This->unk->DP_lock ); - IDirectPlay_AddRef( (LPDIRECTPLAY2A)lpDP ); - return TRUE; } -BOOL DP_DestroyIUnknown( LPVOID lpDP ) +static BOOL DP_DestroyIUnknown( LPVOID lpDP ) { ICOM_THIS(IDirectPlay2AImpl,lpDP); @@ -293,7 +208,7 @@ BOOL DP_DestroyIUnknown( LPVOID lpDP ) return TRUE; } -BOOL DP_CreateDirectPlay2( LPVOID lpDP ) +static BOOL DP_CreateDirectPlay2( LPVOID lpDP ) { ICOM_THIS(IDirectPlay2AImpl,lpDP); @@ -308,46 +223,112 @@ BOOL DP_CreateDirectPlay2( LPVOID lpDP ) This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE; - This->dp2->enumSessionAsyncCallbackData.cb = NULL; - This->dp2->enumSessionAsyncCallbackData.lpContext = NULL; - This->dp2->enumSessionAsyncCallbackData.dwTimeout = INFINITE; - This->dp2->bHostInterface = FALSE; - DPQ_INIT(This->dp2->players); - DPQ_INIT(This->dp2->groups); + DPQ_INIT(This->dp2->receiveMsgs); + DPQ_INIT(This->dp2->sendMsgs); if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) ) { + /* FIXME: Memory leak */ + return FALSE; + } + + /* Provide an initial session desc with nothing in it */ + This->dp2->lpSessionDesc = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof( *This->dp2->lpSessionDesc ) ); + if( This->dp2->lpSessionDesc == NULL ) + { + /* FIXME: Memory leak */ + return FALSE; + } + This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc ); + + /* We are a emulating a dp 6 implementation */ + This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION; + + This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *This->dp2->spData.lpCB ) ); + This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB ); + This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION; + + /* This is the pointer to the service provider */ + if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP, + (LPVOID*)&This->dp2->spData.lpISP, This ) ) + ) + { + /* FIXME: Memory leak */ return FALSE; } return TRUE; } -BOOL DP_DestroyDirectPlay2( LPVOID lpDP ) +/* Definition of the global function in dplayx_queue.h. # + * FIXME: Would it be better to have a dplayx_queue.c for this function? */ +DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID ) +{ + HeapFree( GetProcessHeap(), 0, elem ); +} + +/* Function to delete the list of groups with this interface. Needs to + * delete the group and player lists associated with this group as well + * as the group data associated with this group. It should not delete + * player data as that is shared with the top player list and will be + * deleted with that. + */ +DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList ); +DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList ) +{ + DPQ_DELETEQ( elem->lpGData->groups, groups, + lpGroupList, cbDeleteElemFromHeap ); + DPQ_DELETEQ( elem->lpGData->players, players, + lpPlayerList, cbDeleteElemFromHeap ); + HeapFree( GetProcessHeap(), 0, elem->lpGData ); + HeapFree( GetProcessHeap(), 0, elem ); +} + +/* Function to delete the list of players with this interface. Needs to + * delete the player data for all players as well. + */ +DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList ); +DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList ) +{ + HeapFree( GetProcessHeap(), 0, elem->lpPData ); + HeapFree( GetProcessHeap(), 0, elem ); +} + +static BOOL DP_DestroyDirectPlay2( LPVOID lpDP ) { ICOM_THIS(IDirectPlay2AImpl,lpDP); - FIXME( ": memory leak\n" ); - if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE ) { TerminateThread( This->dp2->hEnumSessionThread, 0 ); CloseHandle( This->dp2->hEnumSessionThread ); } - /* Delete the player and group lists */ +#if 0 + DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem ); + DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem ); +#endif + + /* FIXME: Need to delete receive and send msgs queue contents */ NS_DeleteSessionCache( This->dp2->lpNameServerData ); - + + HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc ); + + IDirectPlaySP_Release( This->dp2->spData.lpISP ); + /* Delete the contents */ HeapFree( GetProcessHeap(), 0, This->dp2 ); return TRUE; } -BOOL DP_CreateDirectPlay3( LPVOID lpDP ) +static BOOL DP_CreateDirectPlay3( LPVOID lpDP ) { ICOM_THIS(IDirectPlay3AImpl,lpDP); @@ -358,12 +339,10 @@ BOOL DP_CreateDirectPlay3( LPVOID lpDP ) return FALSE; } - This->dp3->bConnectionInitialized = FALSE; - return TRUE; } -BOOL DP_DestroyDirectPlay3( LPVOID lpDP ) +static BOOL DP_DestroyDirectPlay3( LPVOID lpDP ) { ICOM_THIS(IDirectPlay3AImpl,lpDP); @@ -373,7 +352,7 @@ BOOL DP_DestroyDirectPlay3( LPVOID lpDP ) return TRUE; } -BOOL DP_CreateDirectPlay4( LPVOID lpDP ) +static BOOL DP_CreateDirectPlay4( LPVOID lpDP ) { ICOM_THIS(IDirectPlay4AImpl,lpDP); @@ -387,7 +366,7 @@ BOOL DP_CreateDirectPlay4( LPVOID lpDP ) return TRUE; } -BOOL DP_DestroyDirectPlay4( LPVOID lpDP ) +static BOOL DP_DestroyDirectPlay4( LPVOID lpDP ) { ICOM_THIS(IDirectPlay3AImpl,lpDP); @@ -398,360 +377,217 @@ BOOL DP_DestroyDirectPlay4( LPVOID lpDP ) } -/* Get a new interface. To be used by QueryInterface. */ +/* Create a new interface */ extern -HRESULT directPlay_QueryInterface +HRESULT DP_CreateInterface ( REFIID riid, LPVOID* ppvObj ) { + TRACE( " for %s\n", debugstr_guid( riid ) ); + + *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( IDirectPlay2Impl ) ); + + if( *ppvObj == NULL ) + { + return DPERR_OUTOFMEMORY; + } if( IsEqualGUID( &IID_IDirectPlay2, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlay2Impl ) ); - - if( *ppvObj == NULL ) - { - return DPERR_OUTOFMEMORY; - } - - /* new scope for variable declaration */ - { - ICOM_THIS(IDirectPlay2Impl,*ppvObj); - - ICOM_VTBL(This) = &directPlay2WVT; - - if ( DP_CreateIUnknown( (LPVOID)This ) && - DP_CreateDirectPlay2( (LPVOID)This ) - ) - { - return S_OK; - } - - } - - goto error; + ICOM_THIS(IDirectPlay2Impl,*ppvObj); + ICOM_VTBL(This) = &directPlay2WVT; } else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlay2AImpl ) ); - - if( *ppvObj == NULL ) - { - return DPERR_OUTOFMEMORY; - } - - /* new scope for variable declaration */ - { - ICOM_THIS(IDirectPlay2AImpl,*ppvObj); - - ICOM_VTBL(This) = &directPlay2AVT; - - if ( DP_CreateIUnknown( (LPVOID)This ) && - DP_CreateDirectPlay2( (LPVOID)This ) - ) - { - return S_OK; - } - - } - - goto error; + ICOM_THIS(IDirectPlay2AImpl,*ppvObj); + ICOM_VTBL(This) = &directPlay2AVT; } else if( IsEqualGUID( &IID_IDirectPlay3, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlay3Impl ) ); - - if( *ppvObj == NULL ) - { - return DPERR_OUTOFMEMORY; - } - - /* new scope for variable declaration */ - { - ICOM_THIS(IDirectPlay3Impl,*ppvObj); - - ICOM_VTBL(This) = &directPlay3WVT; - - if ( DP_CreateIUnknown( (LPVOID)This ) && - DP_CreateDirectPlay2( (LPVOID)This ) && - DP_CreateDirectPlay3( (LPVOID)This ) - ) - { - return S_OK; - } - - } - - goto error; + ICOM_THIS(IDirectPlay3Impl,*ppvObj); + ICOM_VTBL(This) = &directPlay3WVT; } else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlay3AImpl ) ); - - if( *ppvObj == NULL ) - { - return DPERR_OUTOFMEMORY; - } - - /* new scope for variable declaration */ - { - ICOM_THIS(IDirectPlay3AImpl,*ppvObj); - - ICOM_VTBL(This) = &directPlay3AVT; - - if ( DP_CreateIUnknown( (LPVOID)This ) && - DP_CreateDirectPlay2( (LPVOID)This ) && - DP_CreateDirectPlay3( (LPVOID)This ) - ) - { - return S_OK; - } - - } - - goto error; + ICOM_THIS(IDirectPlay3AImpl,*ppvObj); + ICOM_VTBL(This) = &directPlay3AVT; } else if( IsEqualGUID( &IID_IDirectPlay4, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlay4Impl ) ); - - if( *ppvObj == NULL ) - { - return DPERR_OUTOFMEMORY; - } - - /* new scope for variable declaration */ - { - ICOM_THIS(IDirectPlay4Impl,*ppvObj); - - ICOM_VTBL(This) = &directPlay4WVT; - - if ( DP_CreateIUnknown( (LPVOID)This ) && - DP_CreateDirectPlay2( (LPVOID)This ) && - DP_CreateDirectPlay3( (LPVOID)This ) && - DP_CreateDirectPlay4( (LPVOID)This ) - ) - { - return S_OK; - } - - } - - goto error; + ICOM_THIS(IDirectPlay4Impl,*ppvObj); + ICOM_VTBL(This) = &directPlay4WVT; } else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlay4AImpl ) ); + ICOM_THIS(IDirectPlay4AImpl,*ppvObj); + ICOM_VTBL(This) = &directPlay4AVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; - if( *ppvObj == NULL ) - { - return DPERR_OUTOFMEMORY; - } - - /* new scope for variable declaration */ - { - ICOM_THIS(IDirectPlay4AImpl,*ppvObj); - - ICOM_VTBL(This) = &directPlay4AVT; - - if ( DP_CreateIUnknown( (LPVOID)This ) && - DP_CreateDirectPlay2( (LPVOID)This ) && - DP_CreateDirectPlay3( (LPVOID)This ) && - DP_CreateDirectPlay4( (LPVOID)This ) - ) - { - return S_OK; - } - - } - - goto error; + return E_NOINTERFACE; } - /* Unsupported interface */ + /* Initialize it */ + if ( DP_CreateIUnknown( *ppvObj ) && + DP_CreateDirectPlay2( *ppvObj ) && + DP_CreateDirectPlay3( *ppvObj ) && + DP_CreateDirectPlay4( *ppvObj ) + ) + { + IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj ); + + return S_OK; + } + + /* Initialize failed, destroy it */ + DP_DestroyDirectPlay4( *ppvObj ); + DP_DestroyDirectPlay3( *ppvObj ); + DP_DestroyDirectPlay2( *ppvObj ); + DP_DestroyIUnknown( *ppvObj ); + + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; - return E_NOINTERFACE; - -error: - - DP_DestroyDirectPlay4( *ppvObj ); - DP_DestroyDirectPlay3( *ppvObj ); - DP_DestroyDirectPlay2( *ppvObj ); - DP_DestroyIUnknown( *ppvObj ); - HeapFree( GetProcessHeap(), 0, *ppvObj ); - - *ppvObj = NULL; - return DPERR_NOMEMORY; - + return DPERR_NOMEMORY; } /* Direct Play methods */ -static HRESULT WINAPI DirectPlay2W_QueryInterface + +/* Shared between all dplay types */ +static HRESULT WINAPI DP_QueryInterface ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj ) { ICOM_THIS(IDirectPlay2Impl,iface); - TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj ); + TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj ); - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlay2, riid ) - ) + *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( IDirectPlay2Impl ) ); + + if( *ppvObj == NULL ) { - IDirectPlayX_AddRef( iface ); - *ppvObj = This; - return S_OK; - } - return directPlay_QueryInterface( riid, ppvObj ); -} - -static HRESULT WINAPI DirectPlay2A_QueryInterface - ( LPDIRECTPLAY2A iface, REFIID riid, LPVOID* ppvObj ) -{ - ICOM_THIS(IDirectPlay2Impl,iface); - TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj ); - - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlay2A, riid ) - ) - { - IDirectPlayX_AddRef( iface ); - *ppvObj = This; - return S_OK; + return DPERR_OUTOFMEMORY; } - return directPlay_QueryInterface( riid, ppvObj ); -} + CopyMemory( *ppvObj, iface, sizeof( IDirectPlay2Impl ) ); + (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0; -static HRESULT WINAPI DirectPlay3WImpl_QueryInterface - ( LPDIRECTPLAY3 iface, REFIID riid, LPVOID* ppvObj ) -{ - ICOM_THIS(IDirectPlay3Impl,iface); - TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj ); - - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlay3, riid ) - ) + if( IsEqualGUID( &IID_IDirectPlay2, riid ) ) { - IDirectPlayX_AddRef( iface ); - *ppvObj = This; - return S_OK; + ICOM_THIS(IDirectPlay2Impl,*ppvObj); + ICOM_VTBL(This) = &directPlay2WVT; + } + else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) ) + { + ICOM_THIS(IDirectPlay2AImpl,*ppvObj); + ICOM_VTBL(This) = &directPlay2AVT; + } + else if( IsEqualGUID( &IID_IDirectPlay3, riid ) ) + { + ICOM_THIS(IDirectPlay3Impl,*ppvObj); + ICOM_VTBL(This) = &directPlay3WVT; + } + else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) ) + { + ICOM_THIS(IDirectPlay3AImpl,*ppvObj); + ICOM_VTBL(This) = &directPlay3AVT; + } + else if( IsEqualGUID( &IID_IDirectPlay4, riid ) ) + { + ICOM_THIS(IDirectPlay4Impl,*ppvObj); + ICOM_VTBL(This) = &directPlay4WVT; + } + else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) ) + { + ICOM_THIS(IDirectPlay4AImpl,*ppvObj); + ICOM_VTBL(This) = &directPlay4AVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + return E_NOINTERFACE; } - return directPlay_QueryInterface( riid, ppvObj ); + IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj ); + + return S_OK; } -static HRESULT WINAPI DirectPlay3AImpl_QueryInterface - ( LPDIRECTPLAY3A iface, REFIID riid, LPVOID* ppvObj ) -{ - ICOM_THIS(IDirectPlay3Impl,iface); - TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj ); - - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlay3A, riid ) - ) - { - IDirectPlayX_AddRef( iface ); - *ppvObj = This; - return S_OK; - } - - return directPlay_QueryInterface( riid, ppvObj ); -} - -static HRESULT WINAPI DirectPlay4WImpl_QueryInterface - ( LPDIRECTPLAY4 iface, REFIID riid, LPVOID* ppvObj ) -{ - ICOM_THIS(IDirectPlay4Impl,iface); - TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj ); - - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlay4, riid ) - ) - { - IDirectPlayX_AddRef( iface ); - *ppvObj = This; - return S_OK; - } - - return directPlay_QueryInterface( riid, ppvObj ); -} - - -static HRESULT WINAPI DirectPlay4AImpl_QueryInterface - ( LPDIRECTPLAY4A iface, REFIID riid, LPVOID* ppvObj ) -{ - ICOM_THIS(IDirectPlay4Impl,iface); - TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj ); - - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlay4A, riid ) - ) - { - IDirectPlayX_AddRef( iface ); - *ppvObj = This; - return S_OK; - } - - return directPlay_QueryInterface( riid, ppvObj ); -} - - /* Shared between all dplay types */ -static ULONG WINAPI DirectPlay2AImpl_AddRef +static ULONG WINAPI DP_AddRef ( LPDIRECTPLAY3 iface ) { - ULONG refCount; + ULONG ulInterfaceRefCount, ulObjRefCount; ICOM_THIS(IDirectPlay3Impl,iface); - refCount = InterlockedIncrement( &This->unk->ref ); + ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef ); + ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef ); - TRACE("ref count incremented to %lu for %p\n", refCount, This ); + TRACE( "ref count incremented to %lu:%lu for %p\n", + ulInterfaceRefCount, ulObjRefCount, This ); - return refCount; + return ulObjRefCount; } -static ULONG WINAPI DirectPlay2AImpl_Release +static ULONG WINAPI DP_Release ( LPDIRECTPLAY3 iface ) { - ULONG refCount; + ULONG ulInterfaceRefCount, ulObjRefCount; ICOM_THIS(IDirectPlay3Impl,iface); - refCount = InterlockedDecrement( &This->unk->ref ); + ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef ); + ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef ); - TRACE("ref count decremented to %lu for %p\n", refCount, This ); + TRACE( "ref count decremented to %lu:%lu for %p\n", + ulInterfaceRefCount, ulObjRefCount, This ); /* Deallocate if this is the last reference to the object */ - if( refCount == 0 ) + if( ulObjRefCount == 0 ) { + /* If we're destroying the object, this must be the last ref + of the last interface */ DP_DestroyDirectPlay4( This ); DP_DestroyDirectPlay3( This ); DP_DestroyDirectPlay2( This ); DP_DestroyIUnknown( This ); - HeapFree( GetProcessHeap(), 0, This ); + } + + /* Deallocate the interface */ + if( ulInterfaceRefCount == 0 ) + { + HeapFree( GetProcessHeap(), 0, This ); } - return refCount; + return ulObjRefCount; } -static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup - ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer ) +static inline DPID DP_NextObjectId(void) { - lpGroupList lpGList; + return (DPID)InterlockedIncrement( &kludgePlayerGroupId ); +} + + +static HRESULT WINAPI DP_IF_AddPlayerToGroup + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, + DPID idPlayer, BOOL bAnsi ) +{ + lpGroupData lpGData; lpPlayerList lpPList; lpPlayerList lpNewPList; - ICOM_THIS(IDirectPlay2AImpl,iface); - - TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idGroup, idPlayer ); + TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n", + This, lpMsgHdr, idGroup, idPlayer, bAnsi ); /* Find the group */ - if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) { return DPERR_INVALIDGROUP; } @@ -774,86 +610,159 @@ static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup lpNewPList->lpPData = lpPList->lpPData; /* Add the player to the list of players for this group */ - DPQ_INSERT(lpGList->lpGData->players,lpNewPList,players); + DPQ_INSERT(lpGData->players,lpNewPList,players); - /* Send a ADDPLAYERTOGROUP message */ - FIXME( "Not sending message\n" ); + /* Let the SP know that we've added a player to the group */ + if( This->dp2->spData.lpCB->AddPlayerToGroup ) + { + DPSP_ADDPLAYERTOGROUPDATA data; + + TRACE( "Calling SP AddPlayerToGroup\n" ); + + data.idPlayer = idPlayer; + data.idGroup = idGroup; + data.lpISP = This->dp2->spData.lpISP; + + (This->dp2->spData.lpCB->AddPlayerToGroup)( &data ); + } + + /* Inform all other peers of the addition of player to the group. If there are + * no peers keep this event quiet. + * Also, if this event was the result of another machine sending it to us, + * don't bother rebroadcasting it. + */ + if( ( lpMsgHdr == NULL ) && + This->dp2->lpSessionDesc && + ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) ) + { + DPMSG_ADDPLAYERTOGROUP msg; + msg.dwType = DPSYS_ADDPLAYERTOGROUP; + + msg.dpIdGroup = idGroup; + msg.dpIdPlayer = idPlayer; + + /* 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 ); + } return DP_OK; } +static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup + ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer ) +{ + ICOM_THIS(IDirectPlay2Impl,iface); + return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE ); +} + static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idPlayer ); - return DP_OK; + return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE ); } +static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi ) +{ + HRESULT hr = DP_OK; + + FIXME("(%p)->(%u): stub\n", This, bAnsi ); + + /* FIXME: Need to find a new host I assume (how?) */ + /* FIXME: Need to destroy all local groups */ + /* FIXME: Need to migrate all remotely visible players to the new host */ + + /* Invoke the SP callback to inform of session close */ + if( This->dp2->spData.lpCB->CloseEx ) + { + DPSP_CLOSEDATA data; + + TRACE( "Calling SP CloseEx\n" ); + + data.lpISP = This->dp2->spData.lpISP; + + hr = (This->dp2->spData.lpCB->CloseEx)( &data ); + + } + else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */ + { + TRACE( "Calling SP Close (obsolete interface)\n" ); + + hr = (This->dp2->spData.lpCB->Close)(); + } + + /* Even if the SP close failed, we should press on... */ + + /* Invoke the SP callback to inform the SP we don't need it any more */ + if( This->dp2->spData.lpCB->ShutdownEx ) + { + DPSP_SHUTDOWNDATA data; + + TRACE( "Calling SP ShutdownEx\n" ); + + data.lpISP = This->dp2->spData.lpISP; + + hr = (This->dp2->spData.lpCB->ShutdownEx)( &data ); + } + else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */ + { + TRACE( "Calling obsolete SP Shutdown\n" ); + hr = (This->dp2->spData.lpCB->Shutdown)(); + } + + /* Unload the service provider now that we've stoped it */ + FreeLibrary( This->dp2->hServiceProvider ); + + return hr; +} static HRESULT WINAPI DirectPlay2AImpl_Close ( LPDIRECTPLAY2A iface ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(): stub\n", This ); - return DP_OK; + return DP_IF_Close( This, TRUE ); } static HRESULT WINAPI DirectPlay2WImpl_Close ( LPDIRECTPLAY2 iface ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(): stub\n", This ); - return DP_OK; + return DP_IF_Close( This, FALSE ); } static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, LPDPID lpid, - LPDPNAME lpName, lpGroupData lpParentData, - BOOL bAnsi ) + LPDPNAME lpName, DWORD dwFlags, + DPID idParent, BOOL bAnsi ) { - lpGroupList lpGroup; - - TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi ); + lpGroupData lpGData; /* Allocate the new space and add to end of high level group list */ - lpGroup = (lpGroupList) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( *lpGroup ) ); + lpGData = (lpGroupData) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *lpGData ) ); - if( lpGroup == NULL ) + if( lpGData == NULL ) { return NULL; } - /* Allocate storage for the group and associate it with the list element */ - lpGroup->lpGData = (lpGroupData) HeapAlloc( GetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(*(lpGroup->lpGData)) ); + DPQ_INIT(lpGData->groups); + DPQ_INIT(lpGData->players); - if( lpGroup->lpGData == NULL ) - { - /* FIXME: Memory leak */ - return NULL; - } + /* Set the desired player ID - no sanity checking to see if it exists */ + lpGData->dpid = *lpid; - DPQ_INSERT(This->dp2->groups,lpGroup,groups); - - if( *lpid == DPID_UNKNOWN ) - { - /* Assign the next available player ID - FIXME crap solution */ - lpGroup->lpGData->dpid = kludgePlayerGroupId++; - } - else - { - /* Set the desired player ID - no sanity checking to see if it exists */ - lpGroup->lpGData->dpid = *lpid; - } - - DP_CopyDPNAMEStruct( &lpGroup->lpGData->name, lpName, bAnsi ); + DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi ); - lpGroup->lpGData->parent = lpParentData; + /* FIXME: Should we check that the parent exists? */ + lpGData->parent = idParent; - return lpGroup->lpGData; + /* FIXME: Should we validate the dwFlags? */ + lpGData->dwFlags = dwFlags; + + return lpGData; } /* This method assumes that all links to it are already deleted */ @@ -864,7 +773,7 @@ DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid ) TRACE( "(%p)->(0x%08lx)\n", This, dpid ); - DPQ_REMOVE_ENTRY( This->dp2->groups, groups, lpGData->dpid, dpid, lpGList ); + DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList ); if( lpGList == NULL ) { @@ -881,99 +790,205 @@ DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid ) } -/* This function only finds top level groups */ -static lpGroupList DP_FindTopGroup( IDirectPlay2AImpl* This, DPID dpid ) +static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid ) { lpGroupList lpGroups; TRACE( "(%p)->(0x%08lx)\n", This, dpid ); - /* Does the group exist? */ - if( ( lpGroups = DP_FindAnyGroup( This, dpid ) ) == NULL ) + if( dpid == DPID_SYSTEM_GROUP ) { - return NULL; - } - - /* Is this group a top level group? */ - if( lpGroups->lpGData->parent ) - { - return lpGroups; + return This->dp2->lpSysGroup; } else { - return NULL; + DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups ); } + + return lpGroups->lpGData; } -static lpGroupList DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid ) -{ - lpGroupList lpGroups; - - TRACE( "(%p)->(0x%08lx)\n", This, dpid ); - - DPQ_FIND_ENTRY( This->dp2->groups, groups, lpGData->dpid, dpid, lpGroups ); - - return lpGroups; -} - -static HRESULT WINAPI DirectPlay2AImpl_CreateGroup - ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags ) +static HRESULT WINAPI DP_IF_CreateGroup + ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup, + LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, + DWORD dwFlags, BOOL bAnsi ) { lpGroupData lpGData; - ICOM_THIS(IDirectPlay2Impl,iface); + TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n", + This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize, + dwFlags, bAnsi ); - FIXME("(%p)->(%p,%p,%p,0x%08lx,0x%08lx): stub\n", This, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags ); + /* If the name is not specified, we must provide one */ + if( DPID_UNKNOWN == *lpidGroup ) + { + /* If we are the name server, we decide on the group ids. If not, we + * must ask for one before attempting a creation. + */ + if( This->dp2->bHostInterface ) + { + *lpidGroup = DP_NextObjectId(); + } + else + { + /* Request the id from the name server */ + FIXME( "Request id from NS for group\n" ); - lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, - NULL /* Top level group */, TRUE /* Ansi */ ); + /* Hack for now */ + *lpidGroup = DP_NextObjectId(); + } + } + + lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags, + DPID_NOPARENT_GROUP, bAnsi ); if( lpGData == NULL ) { return DPERR_CANTADDPLAYER; /* yes player not group */ } - DP_SetGroupData( lpGData, lpData, dwDataSize ); + if( DPID_SYSTEM_GROUP == *lpidGroup ) + { + This->dp2->lpSysGroup = lpGData; + } + else + { + /* Insert into the system group */ + lpGroupList lpGroup = (lpGroupList) HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof( *lpGroup ) ); + lpGroup->lpGData = lpGData; - /* FIXME: Should send DPMSG_CREATEPLAYERORGROUP message to everyone, - local and remote, that belongs to this session. This will not - be done by calling SetPlayerData */ - FIXME( "Should broadcast group creation to everything in session\n" ); + DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups ); + } + + /* Set all the important stuff for the group */ + DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize ); + + /* FIXME: We should only create the system group if GetCaps returns + * DPCAPS_GROUPOPTIMIZED. + */ + + /* Let the SP know that we've created this group */ + if( This->dp2->spData.lpCB->CreateGroup ) + { + DPSP_CREATEGROUPDATA data; + DWORD dwCreateFlags = 0; + + TRACE( "Calling SP CreateGroup\n" ); + + if( *lpidGroup == DPID_NOPARENT_GROUP ) + dwCreateFlags |= DPLAYI_GROUP_SYSGROUP; + + if( lpMsgHdr == NULL ) + dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL; + + if( dwFlags & DPGROUP_HIDDEN ) + dwCreateFlags |= DPLAYI_GROUP_HIDDEN; + + data.idGroup = *lpidGroup; + data.dwFlags = dwCreateFlags; + data.lpSPMessageHeader = lpMsgHdr; + data.lpISP = This->dp2->spData.lpISP; + + (This->dp2->spData.lpCB->CreateGroup)( &data ); + } + + /* Inform all other peers of the creation of a new group. If there are + * no peers keep this event quiet. + * Also if this message was sent to us, don't rebroadcast. + */ + if( ( lpMsgHdr == NULL ) && + This->dp2->lpSessionDesc && + ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) ) + { + DPMSG_CREATEPLAYERORGROUP msg; + msg.dwType = DPSYS_CREATEPLAYERORGROUP; + + msg.dwPlayerType = DPPLAYERTYPE_GROUP; + msg.dpId = *lpidGroup; + msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */ + msg.lpData = lpData; + msg.dwDataSize = dwDataSize; + msg.dpnName = *lpGroupName; + msg.dpIdParent = DPID_NOPARENT_GROUP; + msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags ); + + /* 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 ); + } return DP_OK; } +static HRESULT WINAPI DirectPlay2AImpl_CreateGroup + ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName, + LPVOID lpData, DWORD dwDataSize, DWORD dwFlags ) +{ + *lpidGroup = DPID_UNKNOWN; + + return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup, + lpGroupName, lpData, dwDataSize, dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_CreateGroup + ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName, + LPVOID lpData, DWORD dwDataSize, DWORD dwFlags ) +{ + *lpidGroup = DPID_UNKNOWN; + + return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup, + lpGroupName, lpData, dwDataSize, dwFlags, FALSE ); +} + + static void -DP_SetGroupData( lpGroupData lpGData, LPVOID lpData, DWORD dwDataSize ) +DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize ) { /* Clear out the data with this player */ - if( lpGData->dwDataSize != 0 ) + if( ( dwFlags & DPSET_LOCAL ) && + ( lpGData->dwLocalDataSize != 0 ) + ) { - HeapFree( GetProcessHeap(), 0, lpGData->lpData ); - lpGData->lpData = NULL; - lpGData->dwDataSize = 0; + HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData ); + lpGData->lpLocalData = NULL; + lpGData->dwLocalDataSize = 0; + } + if( ( dwFlags & DPSET_REMOTE ) && + ( lpGData->dwRemoteDataSize != 0 ) + ) + { + HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData ); + lpGData->lpRemoteData = NULL; + lpGData->dwRemoteDataSize = 0; } /* Reallocate for new data */ - if( lpData ) + if( lpData != NULL ) { - lpGData->lpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( dwDataSize ) ); - memcpy( lpGData->lpData, lpData, dwDataSize ); - lpGData->dwDataSize = dwDataSize; + LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( dwDataSize ) ); + CopyMemory( lpNewData, lpData, dwDataSize ); + + if( dwFlags & DPSET_REMOTE ) + { + lpGData->lpRemoteData = lpNewData; + lpGData->dwRemoteDataSize = dwDataSize; + } + + if( dwFlags & DPSET_LOCAL ) + { + lpGData->lpLocalData = lpData; + lpGData->dwLocalDataSize = dwDataSize; + } } } - -static HRESULT WINAPI DirectPlay2WImpl_CreateGroup - ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags ) -{ - ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(%p,%p,%p,0x%08lx,0x%08lx): stub\n", This, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags ); - return DP_OK; -} - /* This function will just create the storage for the new player. * In the future it may want to intialize, but for the time being * that will be done seperately. @@ -982,50 +997,43 @@ static HRESULT WINAPI DirectPlay2WImpl_CreateGroup */ static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid, - LPDPNAME lpName, HANDLE hEvent, BOOL bAnsi ) + LPDPNAME lpName, DWORD dwFlags, + HANDLE hEvent, BOOL bAnsi ) { - lpPlayerList lpPlayer; + lpPlayerData lpPData; TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi ); - /* Allocate the new space and add to end of interface player list */ - lpPlayer = (lpPlayerList) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( *lpPlayer ) ); - - if( lpPlayer == NULL ) - { - return NULL; - } - /* Allocate the storage for the player and associate it with list element */ - lpPlayer->lpPData = (lpPlayerData) HeapAlloc( GetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(*(lpPlayer->lpPData)) ); - if( lpPlayer->lpPData == NULL ) + lpPData = (lpPlayerData) HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof( *lpPData ) ); + if( lpPData == NULL ) { - /* FIXME: Memory leak */ return NULL; } - /* Insert the player list into the master list of players */ - DPQ_INSERT( This->dp2->players, lpPlayer, players ); + /* Set the desired player ID */ + lpPData->dpid = *lpid; - if( *lpid == DPID_UNKNOWN ) + DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi ); + + lpPData->dwFlags = dwFlags; + + /* If we were given an event handle, duplicate it */ + if( hEvent != 0 ) { - /* Assign the next available player ID - FIXME crap solution */ - lpPlayer->lpPData->dpid = kludgePlayerGroupId++; - } - else - { - /* Set the desired player ID - no sanity checking to see if it exists */ - lpPlayer->lpPData->dpid = *lpid; + if( !DuplicateHandle( GetCurrentProcess(), hEvent, + GetCurrentProcess(), &lpPData->hEvent, + 0, FALSE, DUPLICATE_SAME_ACCESS ) + ) + { + /* FIXME: Memory leak */ + ERR( "Can't duplicate player msg handle %x\n", hEvent ); + } } - DP_CopyDPNAMEStruct( &lpPlayer->lpPData->name, lpName, bAnsi ); - - lpPlayer->lpPData->hEvent = hEvent; - - return lpPlayer->lpPData; + return lpPData; } /* Delete the contents of the DPNAME struct */ @@ -1044,7 +1052,7 @@ DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid ) TRACE( "(%p)->(0x%08lx)\n", This, dpid ); - DPQ_REMOVE_ENTRY( This->dp2->players, players, lpPData->dpid, dpid, lpPlayers ); + DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers ); if( lpPlayers == NULL ) { @@ -1054,11 +1062,12 @@ DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid ) /* Delete player */ DP_DeleteDPNameStruct( &lpPlayers->lpPData->name ); + + CloseHandle( lpPlayers->lpPData->hEvent ); HeapFree( GetProcessHeap(), 0, lpPlayers->lpPData ); /* Delete Player List object */ HeapFree( GetProcessHeap(), 0, lpPlayers ); - } static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid ) @@ -1067,7 +1076,7 @@ static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid ) TRACE( "(%p)->(0x%08lx)\n", This, dpid ); - DPQ_FIND_ENTRY( This->dp2->players, players, lpPData->dpid, dpid, lpPlayers ); + DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers ); return lpPlayers; } @@ -1099,7 +1108,7 @@ static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi ) } /* Copy as required */ - memcpy( lpDst, lpSrc, lpSrc->dwSize ); + CopyMemory( lpDst, lpSrc, lpSrc->dwSize ); if( bAnsi ) { @@ -1136,29 +1145,52 @@ static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi ) } static void -DP_SetPlayerData( lpPlayerData lpPData, LPVOID lpData, DWORD dwDataSize ) +DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize ) { /* Clear out the data with this player */ - if( lpPData->dwDataSize != 0 ) + if( ( dwFlags & DPSET_LOCAL ) && + ( lpPData->dwLocalDataSize != 0 ) + ) { - HeapFree( GetProcessHeap(), 0, lpPData->lpData ); - lpPData->lpData = NULL; - lpPData->dwDataSize = 0; + HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData ); + lpPData->lpLocalData = NULL; + lpPData->dwLocalDataSize = 0; + } + if( ( dwFlags & DPSET_REMOTE ) && + ( lpPData->dwRemoteDataSize != 0 ) + ) + { + HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData ); + lpPData->lpRemoteData = NULL; + lpPData->dwRemoteDataSize = 0; } /* Reallocate for new data */ - if( lpData ) + if( lpData != NULL ) { - lpPData->lpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( dwDataSize ) ); - memcpy( lpPData->lpData, lpData, dwDataSize ); - lpPData->dwDataSize = dwDataSize; + LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( dwDataSize ) ); + CopyMemory( lpNewData, lpData, dwDataSize ); + + if( dwFlags & DPSET_REMOTE ) + { + lpPData->lpRemoteData = lpNewData; + lpPData->dwRemoteDataSize = dwDataSize; + } + + if( dwFlags & DPSET_LOCAL ) + { + lpPData->lpLocalData = lpData; + lpPData->dwLocalDataSize = dwDataSize; + } } - + } static HRESULT WINAPI DP_IF_CreatePlayer ( IDirectPlay2Impl* This, + LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */ LPDPID lpidPlayer, LPDPNAME lpPlayerName, HANDLE hEvent, @@ -1168,6 +1200,7 @@ static HRESULT WINAPI DP_IF_CreatePlayer BOOL bAnsi ) { lpPlayerData lpPData; + lpPlayerList lpPList; TRACE( "(%p)->(%p,%p,%d,%p,0x%08lx,0x%08lx,%u)\n", This, lpidPlayer, lpPlayerName, hEvent, lpData, @@ -1178,6 +1211,11 @@ static HRESULT WINAPI DP_IF_CreatePlayer dwFlags = DPPLAYER_SPECTATOR; } + if( lpidPlayer == NULL ) + { + return DPERR_INVALIDPARAMS; + } + /* Verify we know how to handle all the flags */ if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) || ( dwFlags & DPPLAYER_SPECTATOR ) @@ -1188,29 +1226,32 @@ static HRESULT WINAPI DP_IF_CreatePlayer ERR( "unknown dwFlags = 0x%08lx\n", dwFlags ); } - if ( dwFlags & DPPLAYER_SERVERPLAYER ) + /* If the name is not specified, we must provide one */ + if( *lpidPlayer == DPID_UNKNOWN ) { - /* We have a request to create the "master" of the session. - * This computer needs to be the session host and the server - * player can't have been created yet. - */ - if( ( !This->dp2->bHostInterface ) || - ( DP_FindPlayer( This, DPID_SERVERPLAYER ) ) - ) + /* If we are the session master, we dish out the group/player ids */ + if( This->dp2->bHostInterface ) { - TRACE( "Denying SERVERPLAYER creation\n" ); - return DPERR_CANTCREATEPLAYER; + *lpidPlayer = DP_NextObjectId(); } + else + { + /* Request the id from the name server */ + FIXME( "Request id from NS for new player\n" ); - *lpidPlayer = DPID_SERVERPLAYER; + /* Hack for now */ + *lpidPlayer = DP_NextObjectId(); + } } else { - *lpidPlayer = DPID_UNKNOWN; + /* FIXME: Would be nice to perhaps verify that we don't already have + * this player. + */ } - lpPData = DP_CreatePlayer( This, lpidPlayer, - lpPlayerName, hEvent, bAnsi ); + lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags, + hEvent, bAnsi ); if( lpPData == NULL ) { @@ -1218,13 +1259,87 @@ static HRESULT WINAPI DP_IF_CreatePlayer } /* Update the information and send it to all players in the session */ - DP_SetPlayerData( lpPData, lpData, dwDataSize ); + DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize ); + + /* Create the list object and link it in */ + lpPList = (lpPlayerList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *lpPList ) ); + if( lpPList == NULL ) + { + FIXME( "Memory leak\n" ); + return DPERR_CANTADDPLAYER; + } + + lpPList->lpPData = lpPData; + + DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players ); - /* FIXME: Should send DPMSG_CREATEPLAYERORGROUP message to everyone, - local and remote, that belongs to this session. This will not - be done by calling SetPlayerData */ - FIXME( "Should broadcast player creation to everything in session\n" ); + /* Let the SP know that we've created this player */ + if( This->dp2->spData.lpCB->CreatePlayer ) + { + DPSP_CREATEPLAYERDATA data; + DWORD dwCreateFlags = 0; + + TRACE( "Calling SP CreatePlayer\n" ); + + if( ( dwFlags & DPPLAYER_SERVERPLAYER ) && + ( *lpidPlayer == DPID_SERVERPLAYER ) + ) + dwCreateFlags |= DPLAYI_PLAYER_APPSERVER; + + if( ( dwFlags & DPPLAYER_SERVERPLAYER ) && + ( *lpidPlayer == DPID_NAME_SERVER ) + ) + dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER); + + if( lpMsgHdr == NULL ) + dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL; + + data.idPlayer = *lpidPlayer; + data.dwFlags = dwCreateFlags; + data.lpSPMessageHeader = lpMsgHdr; + data.lpISP = This->dp2->spData.lpISP; + + (This->dp2->spData.lpCB->CreatePlayer)( &data ); + } + + /* FIXME: The native version adds everything to group 0 (similar to + * the player queue that we have. I think that the native + * service providers rely on this fact. + * NOTE: The lpMsgHdr is always non NULL because there is no requirement to + * broadcast this information since every node will automatically + * do it. + */ + DP_IF_AddPlayerToGroup( This, NULL, DPID_NOPARENT_GROUP, + *lpidPlayer, bAnsi ); + + /* Inform all other peers of the creation of a new player. If there are + * no peers keep this quiet. + * Also, if this was a remote event, no need to rebroadcast it. + */ + if( ( lpMsgHdr == NULL ) && + This->dp2->lpSessionDesc && + ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) ) + { + DPMSG_CREATEPLAYERORGROUP msg; + msg.dwType = DPSYS_CREATEPLAYERORGROUP; + + msg.dwPlayerType = DPPLAYERTYPE_PLAYER; + msg.dpId = *lpidPlayer; + msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */ + msg.lpData = lpData; + msg.dwDataSize = dwDataSize; + msg.dpnName = *lpPlayerName; + msg.dpIdParent = DPID_NOPARENT_GROUP; + msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags ); + + /* 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 ); + } return DP_OK; } @@ -1233,7 +1348,17 @@ static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags ) { ICOM_THIS(IDirectPlay2Impl,iface); - return DP_IF_CreatePlayer( This, lpidPlayer, lpPlayerName, hEvent, + + if( dwFlags & DPPLAYER_SERVERPLAYER ) + { + *lpidPlayer = DPID_SERVERPLAYER; + } + else + { + *lpidPlayer = DPID_UNKNOWN; + } + + return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent, lpData, dwDataSize, dwFlags, TRUE ); } @@ -1241,20 +1366,34 @@ static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags ) { ICOM_THIS(IDirectPlay2Impl,iface); - return DP_IF_CreatePlayer( This, lpidPlayer, lpPlayerName, hEvent, + + if( dwFlags & DPPLAYER_SERVERPLAYER ) + { + *lpidPlayer = DPID_SERVERPLAYER; + } + else + { + *lpidPlayer = DPID_UNKNOWN; + } + + return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent, lpData, dwDataSize, dwFlags, FALSE ); } static HRESULT WINAPI DP_IF_DeletePlayerFromGroup - ( IDirectPlay2Impl* This, DPID idGroup, DPID idPlayer, BOOL bAnsi ) + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, + DPID idPlayer, BOOL bAnsi ) { - lpGroupList lpGList; + HRESULT hr = DP_OK; + + lpGroupData lpGData; lpPlayerList lpPList; - TRACE("(%p)->(0x%08lx,0x%08lx,%u)\n", This, idGroup, idPlayer, bAnsi ); + TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n", + This, lpMsgHdr, idGroup, idPlayer, bAnsi ); /* Find the group */ - if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) { return DPERR_INVALIDGROUP; } @@ -1266,34 +1405,48 @@ static HRESULT WINAPI DP_IF_DeletePlayerFromGroup } /* Remove the player shortcut from the group */ - DPQ_REMOVE_ENTRY( lpGList->lpGData->players, players, lpPData->dpid, idPlayer, lpPList ); + DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList ); if( lpPList == NULL ) { - return FALSE; + return DPERR_INVALIDPLAYER; } /* Delete the Player List element */ HeapFree( GetProcessHeap(), 0, lpPList ); + /* Inform the SP if they care */ + if( This->dp2->spData.lpCB->RemovePlayerFromGroup ) + { + DPSP_REMOVEPLAYERFROMGROUPDATA data; + + TRACE( "Calling SP RemovePlayerFromGroup\n" ); + + data.idPlayer = idPlayer; + data.idGroup = idGroup; + data.lpISP = This->dp2->spData.lpISP; + + hr = (This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data ); + } + /* Need to send a DELETEPLAYERFROMGROUP message */ FIXME( "Need to send a message\n" ); - return DP_OK; + return hr; } static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer ) { ICOM_THIS(IDirectPlay2Impl,iface); - return DP_IF_DeletePlayerFromGroup( This, idGroup, idPlayer, TRUE ); + return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE ); } static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer ) { ICOM_THIS(IDirectPlay2Impl,iface); - return DP_IF_DeletePlayerFromGroup( This, idGroup, idPlayer, FALSE ); + return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE ); } typedef struct _DPRGOPContext @@ -1312,6 +1465,7 @@ cbRemoveGroupOrPlayer( LPVOID lpContext ) { lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext; + TRACE( "Removing element:0x%08lx (type:0x%08lx) from element:0x%08lx\n", dpId, dwPlayerType, lpCtxt->idGroup ); @@ -1342,42 +1496,35 @@ cbRemoveGroupOrPlayer( } static HRESULT WINAPI DP_IF_DestroyGroup - ( IDirectPlay2Impl* This, DPID idGroup, BOOL bAnsi ) + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi ) { - lpGroupList lpGList; + lpGroupData lpGData; DPRGOPContext context; - FIXME("(%p)->(0x%08lx,%u): semi stub\n", This, idGroup, bAnsi ); + FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n", + This, lpMsgHdr, idGroup, bAnsi ); /* Find the group */ - if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) { return DPERR_INVALIDPLAYER; /* yes player */ } - /* Yes we're performing a dangerous cast, but it will not be used - unless it's actually a dp3 interface because we will have no - nested groups to delete and we're performing a check below */ context.iface = (LPDIRECTPLAY3)This; context.bAnsi = bAnsi; context.idGroup = idGroup; - /* We should only concern ourselves with a group having groups if this is - DirectPlay 3 or greater */ - if( This->dp3 ) - { - /* Remove all links to groups that this group has since this is dp3 */ - IDirectPlayX_EnumGroupsInGroup( (LPDIRECTPLAY3A)This, idGroup, NULL, - cbRemoveGroupOrPlayer, (LPVOID)&context, 0 ); - /* FIXME: Is it allowed to delete a sub group with a parent? Must be */ - if( lpGList->lpGData->parent ) - { - IDirectPlayX_DeleteGroupFromGroup( (LPDIRECTPLAY3A)This, - lpGList->lpGData->parent->dpid, - idGroup ); - } + /* Remove all links to groups that this group has since this is dp3 */ + IDirectPlayX_EnumGroupsInGroup( (LPDIRECTPLAY3A)This, idGroup, NULL, + cbRemoveGroupOrPlayer, (LPVOID)&context, 0 ); - } + /* FIXME: Is it allowed to delete a sub group with a parent? Must be */ + if( lpGData->parent != DPID_SYSTEM_GROUP ) + { + IDirectPlayX_DeleteGroupFromGroup( (LPDIRECTPLAY3A)This, + lpGData->parent, + idGroup ); + } /* Remove all players that this group has */ IDirectPlayX_EnumGroupPlayers( (LPDIRECTPLAY3A)This, idGroup, NULL, @@ -1386,7 +1533,21 @@ static HRESULT WINAPI DP_IF_DestroyGroup /* Now delete this group data and list */ DP_DeleteGroup( This, idGroup ); - /* Send out a DESTORYPLAYERORGROUP message */ + /* Let the SP know that we've destroyed this group */ + if( This->dp2->spData.lpCB->DeleteGroup ) + { + DPSP_DELETEGROUPDATA data; + + FIXME( "data.dwFlags is incorrect\n" ); + + data.idGroup = idGroup; + data.dwFlags = 0; + data.lpISP = This->dp2->spData.lpISP; + + (This->dp2->spData.lpCB->DeleteGroup)( &data ); + } + + FIXME( "Send out a DESTORYPLAYERORGROUP message\n" ); return DP_OK; } @@ -1395,14 +1556,14 @@ static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup ( LPDIRECTPLAY2A iface, DPID idGroup ) { ICOM_THIS(IDirectPlay2Impl,iface); - return DP_IF_DestroyGroup( This, idGroup, TRUE ); + return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE ); } static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup ( LPDIRECTPLAY2 iface, DPID idGroup ) { ICOM_THIS(IDirectPlay2Impl,iface); - return DP_IF_DestroyGroup( This, idGroup, FALSE ); + return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE ); } typedef struct _DPFAGContext @@ -1412,13 +1573,14 @@ typedef struct _DPFAGContext } DPFAGContext, *lpDPFAGContext; static HRESULT WINAPI DP_IF_DestroyPlayer - ( IDirectPlay2Impl* This, DPID idPlayer, BOOL bAnsi ) + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi ) { DPFAGContext cbContext; - FIXME("(%p)->(0x%08lx,%u): semi stub\n", This, idPlayer, bAnsi ); + FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n", + This, lpMsgHdr, idPlayer, bAnsi ); - if( DP_FindPlayer( This, idPlayer ) ) + if( DP_FindPlayer( This, idPlayer ) == NULL ) { return DPERR_INVALIDPLAYER; } @@ -1436,7 +1598,21 @@ static HRESULT WINAPI DP_IF_DestroyPlayer /* Now delete player and player list */ DP_DeletePlayer( This, idPlayer ); - /* FIXME: Send a DELETEPLAYERORGROUP msg */ + /* Let the SP know that we've destroyed this group */ + if( This->dp2->spData.lpCB->DeletePlayer ) + { + DPSP_DELETEPLAYERDATA data; + + FIXME( "data.dwFlags is incorrect\n" ); + + data.idPlayer = idPlayer; + data.dwFlags = 0; + data.lpISP = This->dp2->spData.lpISP; + + (This->dp2->spData.lpCB->DeletePlayer)( &data ); + } + + FIXME( "Send a DELETEPLAYERORGROUP msg\n" ); return DP_OK; } @@ -1473,14 +1649,14 @@ static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer ( LPDIRECTPLAY2A iface, DPID idPlayer ) { ICOM_THIS(IDirectPlay2Impl,iface); - return DP_IF_DestroyPlayer( This, idPlayer, TRUE ); + return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE ); } static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer ( LPDIRECTPLAY2 iface, DPID idPlayer ) { ICOM_THIS(IDirectPlay2Impl,iface); - return DP_IF_DestroyPlayer( This, idPlayer, FALSE ); + return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE ); } static HRESULT WINAPI DP_IF_EnumGroupPlayers @@ -1488,9 +1664,58 @@ static HRESULT WINAPI DP_IF_EnumGroupPlayers LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ) { - FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): stub\n", + lpGroupData lpGData; + lpPlayerList lpPList; + + FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n", This, idGroup, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags, bAnsi ); + + /* Find the group */ + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + if( DPQ_IS_EMPTY( lpGData->players ) ) + { + return DP_OK; + } + + lpPList = DPQ_FIRST( lpGData->players ); + + /* Walk the players in this group */ + for( ;; ) + { + /* We do not enum the name server or app server as they are of no + * concequence to the end user. + */ + if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) && + ( lpPList->lpPData->dpid != DPID_SERVERPLAYER ) + ) + { + + /* FIXME: Need to add stuff for dwFlags checking */ + + if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER, + &lpPList->lpPData->name, + lpPList->lpPData->dwFlags, + lpContext ) + ) + { + /* User requested break */ + return DP_OK; + } + } + + if( DPQ_IS_ENDOFLIST( lpPList->players ) ) + { + break; + } + + lpPList = DPQ_NEXT( lpPList->players ); + } + return DP_OK; } @@ -1522,38 +1747,10 @@ static HRESULT WINAPI DP_IF_EnumGroups LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ) { - lpGroupList lpGList; - - FIXME("(%p)->(%p,%p,%p,0x%08lx,%u): semi stub\n", - This, lpguidInstance, lpEnumPlayersCallback2, - lpContext, dwFlags, bAnsi ); - - lpGList = This->dp2->groups.lpQHFirst; - - while( lpGList ) - { - /* Is this a top level group? */ - if( lpGList->lpGData->parent ) - { - continue; - } - - /* FIXME: Should check dwFlags for match here */ - - if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP, - &lpGList->lpGData->name, dwFlags, - lpContext ) ) - { - break; /* User requested break */ - } - - if( ( lpGList = lpGList->groups.lpQNext ) == This->dp2->groups.lpQHFirst ) - { - break; - } - } - - return DP_OK; + return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, + DPID_SYSTEM_GROUP, lpguidInstance, + lpEnumPlayersCallback2, lpContext, + dwFlags, bAnsi ); } static HRESULT WINAPI DirectPlay2AImpl_EnumGroups @@ -1581,12 +1778,9 @@ static HRESULT WINAPI DP_IF_EnumPlayers LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ) { - - FIXME("(%p)->(%p,%p,%p,0x%08lx,%u): stub\n", - This, lpguidInstance, lpEnumPlayersCallback2, - lpContext, dwFlags, bAnsi ); - - return DP_OK; + return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance, + lpEnumPlayersCallback2, lpContext, + dwFlags, bAnsi ); } static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers @@ -1624,6 +1818,7 @@ static void DP_InvokeEnumSessionCallbacksA( LPDPENUMSESSIONSCALLBACK2 lpEnumSess NS_ResetSessionEnumeration( lpNSInfo ); /* Enumerate all sessions */ + /* FIXME: Need to indicate ANSI */ while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL ) { TRACE( "EnumSessionsCallback2 invoked\n" ); @@ -1633,106 +1828,165 @@ static void DP_InvokeEnumSessionCallbacksA( LPDPENUMSESSIONSCALLBACK2 lpEnumSess } } + /* Invoke one last time to indicate that there is no more to come */ + lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext ); } -static DWORD CALLBACK DP_EnumSessionsSpwanThreadA( LPVOID lpContext ) +static void DP_InvokeEnumSessionCallbacksW( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, + LPVOID lpNSInfo, + DWORD dwTimeout, + LPVOID lpContext ) { - ICOM_THIS(IDirectPlay2Impl,lpContext); - DWORD dwTimeout = This->dp2->enumSessionAsyncCallbackData.dwTimeout; + LPDPSESSIONDESC2 lpSessionDesc; - TRACE( "(%p)->(0x%08lx)\n", This, dwTimeout ); + FIXME( ": not checking for conditions\n" ); + + NS_ResetSessionEnumeration( lpNSInfo ); + + /* Enumerate all sessions */ + /* FIXME: Need to indicate UNICODE */ + while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL ) + { + TRACE( "EnumSessionsCallback2 invoked\n" ); + if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) ) + { + return; + } + } + + /* Invoke one last time to indicate that there is no more to come */ + lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext ); + +} + +static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext ) +{ + EnumSessionAsyncCallbackData* data = (EnumSessionAsyncCallbackData*)lpContext; + HANDLE hSuicideRequest = data->hSuicideRequest; + DWORD dwTimeout = data->dwTimeout; + + TRACE( "Thread started with timeout = 0x%08lx\n", dwTimeout ); - /* FIXME: Don't think this is exactly right. It'll do for now */ for( ;; ) { - /* 2: Send the broadcast for session enumeration */ - NS_SendSessionRequestBroadcast( This->dp2->lpNameServerData ); + NS_SendSessionRequestBroadcast( &data->requestGuid, + data->dwEnumSessionFlags, + data->lpSpData ); - SleepEx( dwTimeout, FALSE ); - - DP_InvokeEnumSessionCallbacksA( This->dp2->enumSessionAsyncCallbackData.cb, - This->dp2->lpNameServerData, - dwTimeout, - This->dp2->enumSessionAsyncCallbackData.lpContext ); - - /* All sessions have been enumerated. Invoke the callback function - once more indicating a timeout has occured. This is the way - that the application can indicate that it wishes to continue with the - enumeration */ - if( !(This->dp2->enumSessionAsyncCallbackData.cb)( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext ) ) + /* Sleep up to dwTimeout waiting for request to terminate thread */ + if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 ) { - /* The application doesn't want us to continue - end this thread */ - return 0; + TRACE( "Thread terminating on terminate request\n" ); + break; } - } + TRACE( "Thread terminating\n" ); + + /* Clean up the thread data */ + CloseHandle( hSuicideRequest ); + HeapFree( GetProcessHeap(), 0, lpContext ); + return 1; } +static void DP_KillEnumSessionThread( IDirectPlay2Impl* This ) +{ + /* Does a thread exist? If so we were doing an async enum session */ + if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE ) + { + TRACE( "Killing EnumSession thread\n" ); + + /* Request that the thread kill itself nicely */ + SetEvent( This->dp2->hKillEnumSessionThreadEvent ); + CloseHandle( This->dp2->hKillEnumSessionThreadEvent ); + + /* We no longer need to know about the thread */ + CloseHandle( This->dp2->hEnumSessionThread ); + + This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE; + } +} + static HRESULT WINAPI DirectPlay2AImpl_EnumSessions - ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, + ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, + LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, LPVOID lpContext, DWORD dwFlags ) { + HRESULT hr = DP_OK; ICOM_THIS(IDirectPlay2Impl,iface); - TRACE("(%p)->(%p,0x%08lx,%p,%p,0x%08lx)\n", This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags ); + /* FIXME: Combine ANSI and UNICODE versions */ + TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx)\n", + This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags ); + + /* Can't enumerate if the interface is already open */ + if( This->dp2->bConnectionOpen ) + { + return DPERR_GENERIC; + } + + /* Use the service provider default? */ if( dwTimeout == 0 ) { - /* Should actually be getting the dwTimeout value through - IDirectPlay_GetCaps( This, ...) */ - FIXME( ": should provide a dependent dwTimeout\n" ); - dwTimeout = 5 * 1000; /* 5 seconds */ + DPCAPS spCaps; + spCaps.dwSize = sizeof( spCaps ); + + IDirectPlayX_GetCaps( iface, &spCaps, 0 ); + dwTimeout = spCaps.dwTimeout; + + /* FIXME: If it's still 0, we need to provide the IP default */ } if( dwFlags & DPENUMSESSIONS_STOPASYNC ) { - /* Does a thread exist? If so we were doing an async enum session */ - if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE ) - { - /* FIXME: This needs to be send an event to the thread to clean itself up nicely */ - TerminateThread( This->dp2->hEnumSessionThread, 0 ); - CloseHandle( This->dp2->hEnumSessionThread ); - - This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE; - - This->dp2->enumSessionAsyncCallbackData.cb = NULL; - This->dp2->enumSessionAsyncCallbackData.lpContext = NULL; - This->dp2->enumSessionAsyncCallbackData.dwTimeout = INFINITE; - - return DP_OK; - } - - /* Indicate some sort of error... */ - WARN( "STOPASYNC attempted when no async running\n" ); - return DP_OK; + DP_KillEnumSessionThread( This ); + return hr; } /* FIXME: Interface locking sucks in this method */ - if( ( dwFlags & DPENUMSESSIONS_ASYNC ) ) { - DWORD dwThreadId; - /* Enumerate everything presently in the local session cache */ - DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, This->dp2->lpNameServerData, dwTimeout, lpContext ); + DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, + This->dp2->lpNameServerData, dwTimeout, + lpContext ); + /* See if we've already created a thread to service this interface */ if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE ) { - /* FIXME: Should be adding a reference here - another thread now knows - how to call this interface */ - This->dp2->enumSessionAsyncCallbackData.cb = lpEnumSessionsCallback2; - This->dp2->enumSessionAsyncCallbackData.lpContext = lpContext; - This->dp2->enumSessionAsyncCallbackData.dwTimeout = dwTimeout; + DWORD dwThreadId; + EnumSessionAsyncCallbackData* lpData + = (EnumSessionAsyncCallbackData*)HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof( *lpData ) ); + /* FIXME: need to kill the thread on object deletion */ + lpData->lpSpData = &This->dp2->spData; + CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) ); + lpData->dwEnumSessionFlags = dwFlags; + lpData->dwTimeout = dwTimeout; - TRACE( ": creating EnumSessions thread\n" ); + This->dp2->hKillEnumSessionThreadEvent = + CreateEventA( NULL, TRUE, FALSE, NULL ); + + if( !DuplicateHandle( GetCurrentProcess(), + This->dp2->hKillEnumSessionThreadEvent, + GetCurrentProcess(), + &lpData->hSuicideRequest, + 0, FALSE, DUPLICATE_SAME_ACCESS ) + ) + { + ERR( "Can't duplicate thread killing handle\n" ); + } + TRACE( ": creating EnumSessionsRequest thread\n" ); + This->dp2->hEnumSessionThread = CreateThread( NULL, 0, - DP_EnumSessionsSpwanThreadA, - This, + DP_EnumSessionsSendAsyncRequestThread, + lpData, 0, &dwThreadId ); } @@ -1740,66 +1994,205 @@ static HRESULT WINAPI DirectPlay2AImpl_EnumSessions } else { - /* Send the broadcast for session enumeration */ - NS_SendSessionRequestBroadcast( This->dp2->lpNameServerData ); + /* Invalidate the session cache for the interface */ + NS_InvalidateSessionCache( This->dp2->lpNameServerData ); - SleepEx( dwTimeout, FALSE ); - - DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, This->dp2->lpNameServerData, dwTimeout, lpContext ); + /* Send the broadcast for session enumeration */ + hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication, + dwFlags, + &This->dp2->spData ); + + + SleepEx( dwTimeout, FALSE ); + + DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, + This->dp2->lpNameServerData, dwTimeout, lpContext ); } - return DP_OK; + return hr; } static HRESULT WINAPI DirectPlay2WImpl_EnumSessions - ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, + ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, + LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, LPVOID lpContext, DWORD dwFlags ) { + HRESULT hr = DP_OK; ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(%p,0x%08lx,%p,%p,0x%08lx): stub\n", This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags ); - return DP_OK; + + TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx)\n", + This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags ); + + /* Can't enumerate if the interface is already open */ + if( This->dp2->bConnectionOpen ) + { + return DPERR_GENERIC; + } + + /* Use the service provider default? */ + if( dwTimeout == 0 ) + { + DPCAPS spCaps; + spCaps.dwSize = sizeof( spCaps ); + + IDirectPlayX_GetCaps( iface, &spCaps, 0 ); + dwTimeout = spCaps.dwTimeout; + } + + /* FIXME: Interface locking ... */ + + if( dwFlags & DPENUMSESSIONS_STOPASYNC ) + { + DP_KillEnumSessionThread( This ); + + return hr; + } + + /* FIXME: Interface locking sucks in this method */ + + if( ( dwFlags & DPENUMSESSIONS_ASYNC ) ) + { + /* Enumerate everything presently in the local session cache */ + DP_InvokeEnumSessionCallbacksW( lpEnumSessionsCallback2, + This->dp2->lpNameServerData, + dwTimeout, lpContext ); + + /* See if we've already created a thread to service this interface */ + if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE ) + { + DWORD dwThreadId; + + EnumSessionAsyncCallbackData* lpData + = (EnumSessionAsyncCallbackData*)HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof( *lpData ) ); + /* FIXME: need to kill the thread on object deletion */ + lpData->lpSpData = &This->dp2->spData; + CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) ); + lpData->dwEnumSessionFlags = dwFlags; + lpData->dwTimeout = dwTimeout; + + This->dp2->hKillEnumSessionThreadEvent = + CreateEventA( NULL, TRUE, FALSE, NULL ); + + if( !DuplicateHandle( GetCurrentProcess(), + This->dp2->hKillEnumSessionThreadEvent, + GetCurrentProcess(), + &lpData->hSuicideRequest, + 0, FALSE, DUPLICATE_SAME_ACCESS ) + ) + { + ERR( "Can't duplicate thread killing handle\n" ); + } + + + TRACE( ": creating EnumSessionsRequest thread\n" ); + + This->dp2->hEnumSessionThread = CreateThread( NULL, + 0, + DP_EnumSessionsSendAsyncRequestThread, + lpData, + 0, + &dwThreadId ); + } + + } + else + { + /* Invalidate the session cache for the interface */ + NS_InvalidateSessionCache( This->dp2->lpNameServerData ); + + /* Send the broadcast for session enumeration */ + hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication, + dwFlags, + &This->dp2->spData ); + + SleepEx( dwTimeout, FALSE ); + + DP_InvokeEnumSessionCallbacksW( lpEnumSessionsCallback2, + This->dp2->lpNameServerData, + dwTimeout, lpContext ); + } + + return hr; } +static HRESULT WINAPI DP_IF_GetPlayerCaps + ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps, + DWORD dwFlags ) +{ + DPSP_GETCAPSDATA data; + + TRACE("(%p)->(0x%08lx,%p,0x%08lx)\n", This, idPlayer, lpDPCaps, dwFlags); + + /* Query the service provider */ + data.idPlayer = idPlayer; + data.dwFlags = dwFlags; + data.lpCaps = lpDPCaps; + data.lpISP = This->dp2->spData.lpISP; + + return (This->dp2->spData.lpCB->GetCaps)( &data ); +} + + static HRESULT WINAPI DirectPlay2AImpl_GetCaps ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpDPCaps, dwFlags ); - return DP_OK; + return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags ); } static HRESULT WINAPI DirectPlay2WImpl_GetCaps ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpDPCaps, dwFlags ); - return DP_OK; + return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags ); } static HRESULT WINAPI DP_IF_GetGroupData ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi ) { - lpGroupList lpGList; + lpGroupData lpGData; + DWORD dwRequiredBufferSize; + LPVOID lpCopyDataFrom; - FIXME("(%p)->(0x%08lx,%p,%p,0x%08lx,%u): dwFlags ignored\n", - This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi ); + TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n", + This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi ); - if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) { return DPERR_INVALIDGROUP; } + /* How much buffer is required? */ + if( dwFlags & DPSET_REMOTE ) + { + dwRequiredBufferSize = lpGData->dwRemoteDataSize; + lpCopyDataFrom = lpGData->lpRemoteData; + } + else if( dwFlags & DPSET_LOCAL ) + { + dwRequiredBufferSize = lpGData->dwLocalDataSize; + lpCopyDataFrom = lpGData->lpLocalData; + } + else + { + ERR( "Neither local or remote data requested!?!\n" ); + dwRequiredBufferSize = 0; + lpCopyDataFrom = NULL; + } + /* Is the user requesting to know how big a buffer is required? */ if( ( lpData == NULL ) || - ( *lpdwDataSize < lpGList->lpGData->dwDataSize ) + ( *lpdwDataSize < dwRequiredBufferSize ) ) { - *lpdwDataSize = lpGList->lpGData->dwDataSize; + *lpdwDataSize = dwRequiredBufferSize; return DPERR_BUFFERTOOSMALL; } - memcpy( lpData, lpGList->lpGData->lpData, lpGList->lpGData->dwDataSize ); + CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize ); return DP_OK; } @@ -1826,28 +2219,28 @@ static HRESULT WINAPI DP_IF_GetGroupName ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi ) { - lpGroupList lpGList; + lpGroupData lpGData; LPDPNAME lpName = (LPDPNAME)lpData; DWORD dwRequiredDataSize; FIXME("(%p)->(0x%08lx,%p,%p,%u) ANSI ignored\n", This, idGroup, lpData, lpdwDataSize, bAnsi ); - if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) { return DPERR_INVALIDGROUP; } - dwRequiredDataSize = lpGList->lpGData->name.dwSize; + dwRequiredDataSize = lpGData->name.dwSize; - if( lpGList->lpGData->name.psn.lpszShortNameA ) + if( lpGData->name.psn.lpszShortNameA ) { - dwRequiredDataSize += strlen( lpGList->lpGData->name.psn.lpszShortNameA ) + 1; + dwRequiredDataSize += strlen( lpGData->name.psn.lpszShortNameA ) + 1; } - if( lpGList->lpGData->name.pln.lpszLongNameA ) + if( lpGData->name.pln.lpszLongNameA ) { - dwRequiredDataSize += strlen( lpGList->lpGData->name.pln.lpszLongNameA ) + 1; + dwRequiredDataSize += strlen( lpGData->name.pln.lpszLongNameA ) + 1; } if( ( lpData == NULL ) || @@ -1859,22 +2252,22 @@ static HRESULT WINAPI DP_IF_GetGroupName } /* Copy the structure */ - memcpy( lpName, &lpGList->lpGData->name, lpGList->lpGData->name.dwSize ); + CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize ); - if( lpGList->lpGData->name.psn.lpszShortNameA ) + if( lpGData->name.psn.lpszShortNameA ) { - strcpy( ((BYTE*)lpName)+lpGList->lpGData->name.dwSize, - lpGList->lpGData->name.psn.lpszShortNameA ); + strcpy( ((BYTE*)lpName)+lpGData->name.dwSize, + lpGData->name.psn.lpszShortNameA ); } else { lpName->psn.lpszShortNameA = NULL; } - if( lpGList->lpGData->name.psn.lpszShortNameA ) + if( lpGData->name.psn.lpszShortNameA ) { - strcpy( ((BYTE*)lpName)+lpGList->lpGData->name.dwSize, - lpGList->lpGData->name.pln.lpszLongNameA ); + strcpy( ((BYTE*)lpName)+lpGData->name.dwSize, + lpGData->name.pln.lpszLongNameA ); } else { @@ -1900,20 +2293,28 @@ static HRESULT WINAPI DirectPlay2WImpl_GetGroupName return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE ); } +static HRESULT WINAPI DP_IF_GetMessageCount + ( IDirectPlay2Impl* This, DPID idPlayer, + LPDWORD lpdwCount, BOOL bAnsi ) +{ + FIXME("(%p)->(0x%08lx,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi ); + return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer, + DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL, + bAnsi ); +} + static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwCount ); - return DP_OK; + return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE ); } static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwCount ); - return DP_OK; + return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE ); } static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress @@ -1933,19 +2334,19 @@ static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress } static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps - ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps, DWORD dwFlags ) + ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps, + DWORD dwFlags ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(0x%08lx,%p,0x%08lx): stub\n", This, idPlayer, lpPlayerCaps, dwFlags ); - return DP_OK; + return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags ); } static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps - ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps, DWORD dwFlags ) + ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps, + DWORD dwFlags ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(0x%08lx,%p,0x%08lx): stub\n", This, idPlayer, lpPlayerCaps, dwFlags ); - return DP_OK; + return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags ); } static HRESULT WINAPI DP_IF_GetPlayerData @@ -1953,8 +2354,10 @@ static HRESULT WINAPI DP_IF_GetPlayerData LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi ) { lpPlayerList lpPList; + DWORD dwRequiredBufferSize; + LPVOID lpCopyDataFrom; - FIXME( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u): stub\n", + TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n", This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi ); if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL ) @@ -1962,16 +2365,34 @@ static HRESULT WINAPI DP_IF_GetPlayerData return DPERR_INVALIDPLAYER; } + /* How much buffer is required? */ + if( dwFlags & DPSET_REMOTE ) + { + dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize; + lpCopyDataFrom = lpPList->lpPData->lpRemoteData; + } + else if( dwFlags & DPSET_LOCAL ) + { + dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize; + lpCopyDataFrom = lpPList->lpPData->lpLocalData; + } + else + { + ERR( "Neither local or remote data requested!?!\n" ); + dwRequiredBufferSize = 0; + lpCopyDataFrom = NULL; + } + /* Is the user requesting to know how big a buffer is required? */ if( ( lpData == NULL ) || - ( *lpdwDataSize < lpPList->lpPData->dwDataSize ) + ( *lpdwDataSize < dwRequiredBufferSize ) ) { - *lpdwDataSize = lpPList->lpPData->dwDataSize; + *lpdwDataSize = dwRequiredBufferSize; return DPERR_BUFFERTOOSMALL; } - memcpy( lpData, lpPList->lpPData->lpData, lpPList->lpPData->dwDataSize ); + CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize ); return DP_OK; } @@ -2031,7 +2452,7 @@ static HRESULT WINAPI DP_IF_GetPlayerName } /* Copy the structure */ - memcpy( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize ); + CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize ); if( lpPList->lpPData->name.psn.lpszShortNameA ) { @@ -2072,20 +2493,47 @@ static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE ); } +static HRESULT WINAPI DP_GetSessionDesc + ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize, + BOOL bAnsi ) +{ + DWORD dwRequiredSize; + + TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi ); + + if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) ) + { + return DPERR_INVALIDPARAMS; + } + + /* FIXME: Get from This->dp2->lpSessionDesc */ + dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi ); + + if ( ( lpData == NULL ) || + ( *lpdwDataSize < dwRequiredSize ) + ) + { + *lpdwDataSize = dwRequiredSize; + return DPERR_BUFFERTOOSMALL; + } + + DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi ); + + return DP_OK; +} + static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(%p,%p): stub\n", This, lpData, lpdwDataSize ); - return DP_OK; + return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE ); } static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(%p,%p): stub\n", This, lpData, lpdwDataSize ); - return DP_OK; + return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE ); } /* Intended only for COM compatibility. Always returns an error. */ @@ -2109,9 +2557,12 @@ static HRESULT WINAPI DirectPlay2WImpl_Initialize static HRESULT WINAPI DP_SecureOpen ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags, - LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials ) + LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials, + BOOL bAnsi ) { - FIXME( "(%p)->(%p,0x%08lx,%p,%p): semi stub\n", + HRESULT hr = DP_OK; + + FIXME( "(%p)->(%p,0x%08lx,%p,%p): partial stub\n", This, lpsd, dwFlags, lpSecurity, lpCredentials ); if( This->dp2->bConnectionOpen ) @@ -2120,28 +2571,76 @@ static HRESULT WINAPI DP_SecureOpen return DPERR_ALREADYINITIALIZED; } - /* When we open we need to stop any EnumSession activity */ - /* FIXME: Perhaps some sort of internal interface would be better */ - IDirectPlayX_EnumSessions( (LPDIRECTPLAY2A)This, NULL, 0, NULL, NULL, - DPENUMSESSIONS_STOPASYNC ); + /* If we're enumerating, kill the thread */ + DP_KillEnumSessionThread( This ); if( dwFlags & DPOPEN_CREATE ) { - dwFlags &= ~DPOPEN_CREATE; - /* Rightoo - this computer is the host and the local computer needs to be the name server so that others can join this session */ NS_SetLocalComputerAsNameServer( lpsd ); This->dp2->bHostInterface = TRUE; + + hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi ); + if( FAILED( hr ) ) + { + ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) ); + return hr; + } } - if( dwFlags ) + /* Invoke the conditional callback for the service provider */ + if( This->dp2->spData.lpCB->Open ) { - ERR( ": ignored dwFlags 0x%08lx\n", dwFlags ); + DPSP_OPENDATA data; + + FIXME( "Not all data fields are correct. Need new parameter\n" ); + + data.bCreate = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE; + data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL + : NS_GetNSAddr( This->dp2->lpNameServerData ); + data.lpISP = This->dp2->spData.lpISP; + data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE; + data.dwOpenFlags = dwFlags; + data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags; + + hr = (This->dp2->spData.lpCB->Open)(&data); + } + + { + /* FIXME: DPLAY creates this after the name server... */ + DPID systemGroup = DPID_SYSTEM_GROUP; + + hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL, + NULL, 0, 0, TRUE ); + } - return DP_OK; + if( dwFlags & DPOPEN_JOIN ) + { + DPID dpidServerId = DPID_SERVERPLAYER; + + /* Create the server player for this interface. This way we can receive + * messages for this session. + */ + /* FIXME: I suppose that we should be setting an event for a receive + * type of thing. That way the messaging thread could know to wake + * up. DPlay would then trigger the hEvent for the player the + * message is directed to. + */ + hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL, + 0, DPPLAYER_SERVERPLAYER, bAnsi ); + } + else if( dwFlags & DPOPEN_CREATE ) + { + DPID dpidNameServerId = DPID_NAME_SERVER; + + hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL, + 0, DPPLAYER_SERVERPLAYER, bAnsi ); + } + + return hr; } static HRESULT WINAPI DirectPlay2AImpl_Open @@ -2149,7 +2648,7 @@ static HRESULT WINAPI DirectPlay2AImpl_Open { ICOM_THIS(IDirectPlay2Impl,iface); TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags ); - return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL ); + return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE ); } static HRESULT WINAPI DirectPlay2WImpl_Open @@ -2157,48 +2656,103 @@ static HRESULT WINAPI DirectPlay2WImpl_Open { ICOM_THIS(IDirectPlay2Impl,iface); TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags ); - return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL ); + return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE ); +} + +static HRESULT WINAPI DP_IF_Receive + ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo, + DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi ) +{ + LPDPMSG lpMsg = NULL; + + FIXME( "(%p)->(%p,%p,0x%08lx,%p,%p,%u): stub\n", + This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi ); + + if( dwFlags == 0 ) + { + dwFlags = DPRECEIVE_ALL; + } + + /* If the lpData is NULL, we must be peeking the message */ + if( ( lpData == NULL ) && + !( dwFlags & DPRECEIVE_PEEK ) + ) + { + return DPERR_INVALIDPARAMS; + } + + if( dwFlags & DPRECEIVE_ALL ) + { + lpMsg = This->dp2->receiveMsgs.lpQHFirst; + + if( !( dwFlags & DPRECEIVE_PEEK ) ) + { + FIXME( "Remove from queue\n" ); + } + } + else if( ( dwFlags & DPRECEIVE_TOPLAYER ) || + ( dwFlags & DPRECEIVE_FROMPLAYER ) + ) + { + FIXME( "Find matching message 0x%08lx\n", dwFlags ); + } + else + { + ERR( "Hmmm..dwFlags 0x%08lx\n", dwFlags ); + } + + if( lpMsg == NULL ) + { + return DPERR_NOMESSAGES; + } + + /* Copy into the provided buffer */ + CopyMemory( lpData, lpMsg->msg, *lpdwDataSize ); + + return DP_OK; } static HRESULT WINAPI DirectPlay2AImpl_Receive - ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize ) + ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo, + DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(%p,%p,0x%08lx,%p,%p): stub\n", This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize ); - return DP_OK; + return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, + lpData, lpdwDataSize, TRUE ); } static HRESULT WINAPI DirectPlay2WImpl_Receive - ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize ) + ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo, + DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(%p,%p,0x%08lx,%p,%p): stub\n", This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize ); - return DP_OK; + return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, + lpData, lpdwDataSize, FALSE ); } static HRESULT WINAPI DirectPlay2AImpl_Send ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx): stub\n", This, idFrom, idTo, dwFlags, lpData, dwDataSize ); - return DP_OK; + return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize, + 0, 0, NULL, NULL, TRUE ); } static HRESULT WINAPI DirectPlay2WImpl_Send ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx): stub\n", This, idFrom, idTo, dwFlags, lpData, dwDataSize ); - return DP_OK; + return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize, + 0, 0, NULL, NULL, FALSE ); } static HRESULT WINAPI DP_IF_SetGroupData ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi ) { - lpGroupList lpGList; + lpGroupData lpGData; - FIXME( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u): dwFlags ignored\n", + TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n", This, idGroup, lpData, dwDataSize, dwFlags, bAnsi ); /* Parameter check */ @@ -2210,12 +2764,28 @@ static HRESULT WINAPI DP_IF_SetGroupData } /* Find the pointer to the data for this player */ - if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) { return DPERR_INVALIDOBJECT; } - DP_SetGroupData( lpGList->lpGData, lpData, dwDataSize ); + if( dwFlags & DPSET_REMOTE ) + { + FIXME( "Was this group created by this interface?\n" ); + /* FIXME: If this is a remote update need to allow it but not + * send a message. + */ + } + + DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize ); + + /* FIXME: Only send a message if this group is local to the session otherwise + * it will have been rejected above + */ + if( dwFlags & DPSET_REMOTE ) + { + FIXME( "Send msg?\n" ); + } return DP_OK; } @@ -2240,17 +2810,17 @@ static HRESULT WINAPI DP_IF_SetGroupName ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName, DWORD dwFlags, BOOL bAnsi ) { - lpGroupList lpGList; + lpGroupData lpGData; TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", This, idGroup, lpGroupName, dwFlags, bAnsi ); - if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) { return DPERR_INVALIDGROUP; } - DP_CopyDPNAMEStruct( &lpGList->lpGData->name, lpGroupName, bAnsi ); + DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi ); /* Should send a DPMSG_SETPLAYERORGROUPNAME message */ FIXME( "Message not sent and dwFlags ignored\n" ); @@ -2297,11 +2867,19 @@ static HRESULT WINAPI DP_IF_SetPlayerData return DPERR_INVALIDPLAYER; } - DP_SetPlayerData( lpPList->lpPData, lpData, dwDataSize ); - - if( !(dwFlags & DPSET_LOCAL ) ) /* Is DPSET_REMOTE? */ + if( dwFlags & DPSET_REMOTE ) { - FIXME( "Change not propagated to all players in the session\n" ); + FIXME( "Was this group created by this interface?\n" ); + /* FIXME: If this is a remote update need to allow it but not + * send a message. + */ + } + + DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize ); + + if( dwFlags & DPSET_REMOTE ) + { + FIXME( "Send msg?\n" ); } return DP_OK; @@ -2363,37 +2941,190 @@ static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE ); } +static HRESULT WINAPI DP_SetSessionDesc + ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc, + DWORD dwFlags, BOOL bInitial, BOOL bAnsi ) +{ + DWORD dwRequiredSize; + LPDPSESSIONDESC2 lpTempSessDesc; + + TRACE( "(%p)->(%p,0x%08lx,%u,%u)\n", + This, lpSessDesc, dwFlags, bInitial, bAnsi ); + + if( dwFlags ) + { + return DPERR_INVALIDPARAMS; + } + + /* Only the host is allowed to update the session desc */ + if( !This->dp2->bHostInterface ) + { + return DPERR_ACCESSDENIED; + } + + /* FIXME: Copy into This->dp2->lpSessionDesc */ + dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi ); + lpTempSessDesc = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + dwRequiredSize ); + + if( lpTempSessDesc == NULL ) + { + return DPERR_OUTOFMEMORY; + } + + /* Free the old */ + HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc ); + + This->dp2->lpSessionDesc = lpTempSessDesc; + + /* Set the new */ + DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi ); + + /* If this is an external invocation of the interface, we should be + * letting everyone know that things have changed. Otherwise this is + * just an initialization and it doesn't need to be propagated. + */ + if( !bInitial ) + { + FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" ); + } + + return DP_OK; +} + static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpSessDesc, dwFlags ); - return DP_OK; + return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE ); } static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags ) { ICOM_THIS(IDirectPlay2Impl,iface); - FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpSessDesc, dwFlags ); - return DP_OK; + return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE ); } +/* FIXME: See about merging some of this stuff with dplayx_global.c stuff */ +DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi ) +{ + DWORD dwSize = 0; + + if( lpSessDesc == NULL ) + { + /* Hmmm..don't need any size? */ + ERR( "NULL lpSessDesc\n" ); + return dwSize; + } + + dwSize += sizeof( *lpSessDesc ); + + if( bAnsi ) + { + if( lpSessDesc->sess.lpszSessionNameA ) + { + dwSize += lstrlenA( lpSessDesc->sess.lpszSessionNameA ) + 1; + } + + if( lpSessDesc->pass.lpszPasswordA ) + { + dwSize += lstrlenA( lpSessDesc->pass.lpszPasswordA ) + 1; + } + } + else /* UNICODE */ + { + if( lpSessDesc->sess.lpszSessionName ) + { + dwSize += sizeof( WCHAR ) * + ( lstrlenW( lpSessDesc->sess.lpszSessionName ) + 1 ); + } + + if( lpSessDesc->pass.lpszPassword ) + { + dwSize += sizeof( WCHAR ) * + ( lstrlenW( lpSessDesc->pass.lpszPassword ) + 1 ); + } + } + + return dwSize; +} + +/* Assumes that contugous buffers are already allocated. */ +static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest, + LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi ) +{ + BYTE* lpStartOfFreeSpace; + + if( lpSessionDest == NULL ) + { + ERR( "NULL lpSessionDest\n" ); + return; + } + + CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) ); + + lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc ); + + if( bAnsi ) + { + if( lpSessionSrc->sess.lpszSessionNameA ) + { + lstrcpyA( (LPSTR)lpStartOfFreeSpace, + lpSessionDest->sess.lpszSessionNameA ); + lpSessionDest->sess.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += + lstrlenA( (LPSTR)lpSessionDest->sess.lpszSessionNameA ) + 1; + } + + if( lpSessionSrc->pass.lpszPasswordA ) + { + lstrcpyA( (LPSTR)lpStartOfFreeSpace, + lpSessionDest->pass.lpszPasswordA ); + lpSessionDest->pass.lpszPasswordA = (LPSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += + lstrlenA( (LPSTR)lpSessionDest->pass.lpszPasswordA ) + 1; + } + } + else /* UNICODE */ + { + if( lpSessionSrc->sess.lpszSessionName ) + { + lstrcpyW( (LPWSTR)lpStartOfFreeSpace, + lpSessionDest->sess.lpszSessionName ); + lpSessionDest->sess.lpszSessionName = (LPWSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof(WCHAR) * + ( lstrlenW( (LPWSTR)lpSessionDest->sess.lpszSessionName ) + 1 ); + } + + if( lpSessionSrc->pass.lpszPassword ) + { + lstrcpyW( (LPWSTR)lpStartOfFreeSpace, + lpSessionDest->pass.lpszPassword ); + lpSessionDest->pass.lpszPassword = (LPWSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof(WCHAR) * + ( lstrlenW( (LPWSTR)lpSessionDest->pass.lpszPassword ) + 1 ); + } + } +} + + static HRESULT WINAPI DP_IF_AddGroupToGroup ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup ) { - lpGroupList lpGParentList; - lpGroupList lpGList; + lpGroupData lpGParentData; + lpGroupData lpGData; lpGroupList lpNewGList; TRACE( "(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup ); - if( ( lpGParentList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL ) + if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL ) { return DPERR_INVALIDGROUP; } - if( ( lpGList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL ) + if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL ) { return DPERR_INVALIDGROUP; } @@ -2407,10 +3138,10 @@ static HRESULT WINAPI DP_IF_AddGroupToGroup } /* Add the shortcut */ - lpNewGList->lpGData = lpGList->lpGData; + lpNewGList->lpGData = lpGData; /* Add the player to the list of players for this group */ - DPQ_INSERT( lpGList->lpGData->groups, lpNewGList, groups ); + DPQ_INSERT( lpGData->groups, lpNewGList, groups ); /* Send a ADDGROUPTOGROUP message */ FIXME( "Not sending message\n" ); @@ -2433,20 +3164,20 @@ static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup } static HRESULT WINAPI DP_IF_CreateGroupInGroup - ( IDirectPlay3Impl* This, DPID idParentGroup, LPDPID lpidGroup, - LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, - DWORD dwFlags ) + ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup, + LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData, + DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi ) { - lpGroupList lpGParentList; + lpGroupData lpGParentData; lpGroupList lpGList; lpGroupData lpGData; - TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx)\n", + TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,%u)\n", This, idParentGroup, lpidGroup, lpGroupName, lpData, - dwDataSize, dwFlags ); + dwDataSize, dwFlags, bAnsi ); /* Verify that the specified parent is valid */ - if( ( lpGParentList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, + if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL ) { @@ -2454,14 +3185,14 @@ static HRESULT WINAPI DP_IF_CreateGroupInGroup } lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName, - lpGParentList->lpGData, TRUE /* Ansi */ ); + dwFlags, idParentGroup, bAnsi ); if( lpGData == NULL ) { return DPERR_CANTADDPLAYER; /* yes player not group */ } - DP_SetGroupData( lpGData, lpData, dwDataSize ); + DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize ); /* The list has now been inserted into the interface group list. We now need to put a "shortcut" to this group in the parent group */ @@ -2475,13 +3206,46 @@ static HRESULT WINAPI DP_IF_CreateGroupInGroup lpGList->lpGData = lpGData; - DPQ_INSERT( lpGParentList->lpGData->groups, lpGList, groups ); - + DPQ_INSERT( lpGParentData->groups, lpGList, groups ); - /* FIXME: Should send DPMSG_CREATEPLAYERORGROUP message to everyone, - local and remote, that belongs to this session. This will not - be done by calling SetPlayerData */ - FIXME( "Should broadcast group creation to everything in session\n" ); + /* Let the SP know that we've created this group */ + if( This->dp2->spData.lpCB->CreateGroup ) + { + DPSP_CREATEGROUPDATA data; + + TRACE( "Calling SP CreateGroup\n" ); + + data.idGroup = *lpidGroup; + data.dwFlags = dwFlags; + data.lpSPMessageHeader = lpMsgHdr; + data.lpISP = This->dp2->spData.lpISP; + + (This->dp2->spData.lpCB->CreateGroup)( &data ); + } + + /* Inform all other peers of the creation of a new group. If there are + * no peers keep this quiet. + */ + if( This->dp2->lpSessionDesc && + ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) ) + { + DPMSG_CREATEPLAYERORGROUP msg; + + msg.dwType = DPSYS_CREATEPLAYERORGROUP; + msg.dwPlayerType = DPPLAYERTYPE_GROUP; + msg.dpId = *lpidGroup; + msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */ + msg.lpData = lpData; + msg.dwDataSize = dwDataSize; + msg.dpnName = *lpGroupName; + + /* FIXME: Correct to just use send effectively? */ + /* FIXME: Should size include data w/ message or just message "header" */ + /* FIXME: Check return code */ + DP_SendEx( (IDirectPlay2Impl*)This, + DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), + 0, 0, NULL, NULL, bAnsi ); + } return DP_OK; } @@ -2492,8 +3256,12 @@ static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup DWORD dwFlags ) { ICOM_THIS(IDirectPlay3Impl,iface); - return DP_IF_CreateGroupInGroup( This, idParentGroup, lpidGroup, lpGroupName, - lpData, dwDataSize, dwFlags ); + + *lpidGroup = DPID_UNKNOWN; + + return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, + lpGroupName, lpData, dwDataSize, dwFlags, + TRUE ); } static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup @@ -2502,26 +3270,30 @@ static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup DWORD dwFlags ) { ICOM_THIS(IDirectPlay3Impl,iface); - return DP_IF_CreateGroupInGroup( This, idParentGroup, lpidGroup, lpGroupName, - lpData, dwDataSize, dwFlags ); + + *lpidGroup = DPID_UNKNOWN; + + return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, + lpGroupName, lpData, dwDataSize, + dwFlags, FALSE ); } static HRESULT WINAPI DP_IF_DeleteGroupFromGroup ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup ) { lpGroupList lpGList; - lpGroupList lpGParentList; + lpGroupData lpGParentData; TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup ); /* Is the parent group valid? */ - if( ( lpGParentList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL ) + if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL ) { return DPERR_INVALIDGROUP; } /* Remove the group from the parent group queue */ - DPQ_REMOVE_ENTRY( lpGParentList->lpGData->groups, groups, lpGData->dpid, idGroup, lpGList ); + DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList ); if( lpGList == NULL ) { @@ -2650,8 +3422,9 @@ static HRESULT WINAPI DirectPlay3AImpl_EnumConnections allocating an 80 byte buffer which isn't even a filled with a valid compound address. Oh well. Creating a proper compound address is the way to go anyways despite this method taking slightly more heap space and realtime :) */ - dpCompoundAddress.guidDataType = DPAID_ServiceProvider; dpCompoundAddress.dwDataSize = sizeof( GUID ); + memcpy( &dpCompoundAddress.guidDataType, &DPAID_ServiceProvider, + sizeof( GUID ) ) ; dpCompoundAddress.lpData = &serviceProviderGUID; if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer, @@ -2675,8 +3448,6 @@ static HRESULT WINAPI DirectPlay3AImpl_EnumConnections if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize, &dpName, DPCONNECTION_DIRECTPLAY, lpContext ) ) { - WARN("lpEnumCallback returning FALSE\n" ); - return DP_OK; } } @@ -2702,7 +3473,7 @@ static HRESULT WINAPI DirectPlay3AImpl_EnumConnections } - /* Traverse all the service providers we have available */ + /* Traverse all the lobby providers we have available */ for( dwIndex=0; RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName, NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS; @@ -2757,7 +3528,7 @@ static HRESULT WINAPI DirectPlay3AImpl_EnumConnections allocating an 80 byte buffer which isn't even a filled with a valid compound address. Oh well. Creating a proper compound address is the way to go anyways despite this method taking slightly more heap space and realtime :) */ - dpCompoundAddress.guidDataType = DPAID_ServiceProvider; + dpCompoundAddress.guidDataType = DPAID_LobbyProvider; dpCompoundAddress.dwDataSize = sizeof( GUID ); dpCompoundAddress.lpData = &serviceProviderGUID; @@ -2780,10 +3551,8 @@ static HRESULT WINAPI DirectPlay3AImpl_EnumConnections /* The enumeration will return FALSE if we are not to continue */ if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize, - &dpName, DPCONNECTION_DIRECTPLAY, lpContext ) ) + &dpName, DPCONNECTION_DIRECTPLAYLOBBY, lpContext ) ) { - WARN("lpEnumCallback returning FALSE\n" ); - return DP_OK; } } @@ -2800,48 +3569,73 @@ static HRESULT WINAPI DirectPlay3WImpl_EnumConnections return DP_OK; } -static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup - ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, DWORD dwFlags ) +static HRESULT WINAPI DP_IF_EnumGroupsInGroup + ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ) { lpGroupList lpGList; - lpGroupList lpGiGList; - ICOM_THIS(IDirectPlay3AImpl,iface); + lpGroupData lpGData; - FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx): semi stub\n", This, idGroup, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags ); + FIXME( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n", + This, idGroup, lpguidInstance, lpEnumPlayersCallback2, + lpContext, dwFlags, bAnsi ); - if( ( lpGList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL ) + if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL ) { return DPERR_INVALIDGROUP; } - lpGiGList = lpGList->lpGData->groups.lpQHFirst; - - while( lpGiGList ) + if( DPQ_IS_EMPTY( lpGData->groups ) ) { - /* FIXME: Should check dwFlags for match here */ + return DP_OK; + } - if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP, - &lpGList->lpGData->name, dwFlags, - lpContext ) ) - { - return DP_OK; /* User requested break */ - } + lpGList = DPQ_FIRST( lpGData->groups ); + + for( ;; ) + { + /* FIXME: Should check dwFlags for match here */ + + if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP, + &lpGList->lpGData->name, dwFlags, + lpContext ) ) + { + return DP_OK; /* User requested break */ + } + + if( DPQ_IS_ENDOFLIST( lpGList->groups ) ) + { + break; + } + + lpGList = DPQ_NEXT( lpGList->groups ); - if( ( lpGiGList = lpGiGList->groups.lpQNext ) == lpGList->lpGData->groups.lpQHFirst ) - { - return DP_OK; /* End of groups */ - } } return DP_OK; } -static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup - ( LPDIRECTPLAY3 iface, DPID idGroup, LPGUID lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, DWORD dwFlags ) +static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup + ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, + DWORD dwFlags ) { ICOM_THIS(IDirectPlay3Impl,iface); - FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx): stub\n", This, idGroup, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags ); - return DP_OK; + return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance, + lpEnumPlayersCallback2, lpContext, dwFlags, + TRUE ); +} + +static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup + ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, + DWORD dwFlags ) +{ + ICOM_THIS(IDirectPlay3Impl,iface); + return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance, + lpEnumPlayersCallback2, lpContext, dwFlags, + FALSE ); } static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings @@ -2860,33 +3654,204 @@ static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings return DP_OK; } +BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress( + REFGUID guidDataType, + DWORD dwDataSize, + LPCVOID lpData, + LPVOID lpContext ) +{ + /* Looking for the GUID of the provider to load */ + if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) || + ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) ) + ) + { + TRACE( "Found SP/LP (%s) %s (data size = 0x%08lx)\n", + debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize ); + + if( dwDataSize != sizeof( GUID ) ) + { + ERR( "Invalid sp/lp guid size 0x%08lx\n", dwDataSize ); + } + + memcpy( lpContext, lpData, dwDataSize ); + + /* There shouldn't be more than 1 GUID/compound address */ + return FALSE; + } + + /* Still waiting for what we want */ + return TRUE; +} + + +/* Find and perform a LoadLibrary on the requested SP or LP GUID */ +static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData ) +{ + UINT i; + LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers"; + LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers"; + LPCSTR guidDataSubKey = "Guid"; + LPCSTR majVerDataSubKey = "dwReserved1"; + LPCSTR minVerDataSubKey = "dwReserved2"; + LPCSTR pathSubKey = "Path"; + + TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) ); + + /* FIXME: Cloned code with a quick hack. */ + for( i=0; i<2; i++ ) + { + HKEY hkResult; + LPCSTR searchSubKey; + char subKeyName[51]; + DWORD dwIndex, sizeOfSubKeyName=50; + FILETIME filetime; + + (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey ); + + + /* Need to loop over the service providers in the registry */ + if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey, + 0, KEY_READ, &hkResult ) != ERROR_SUCCESS ) + { + /* Hmmm. Does this mean that there are no service providers? */ + ERR(": no service providers?\n"); + return 0; + } + + /* Traverse all the service providers we have available */ + for( dwIndex=0; + RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName, + NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS; + ++dwIndex, sizeOfSubKeyName=51 ) + { + + HKEY hkServiceProvider; + GUID serviceProviderGUID; + DWORD returnType, sizeOfReturnBuffer = 255; + char returnBuffer[256]; + LPWSTR lpWGUIDString; + DWORD dwTemp; + + TRACE(" this time through: %s\n", subKeyName ); + + /* Get a handle for this particular service provider */ + if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ, + &hkServiceProvider ) != ERROR_SUCCESS ) + { + ERR(": what the heck is going on?\n" ); + continue; + } + + if( RegQueryValueExA( hkServiceProvider, guidDataSubKey, + NULL, &returnType, returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR(": missing GUID registry data members\n" ); + continue; + } + + /* FIXME: Check return types to ensure we're interpreting data right */ + lpWGUIDString = HEAP_strdupAtoW( GetProcessHeap(), 0, returnBuffer ); + CLSIDFromString( (LPCOLESTR)lpWGUIDString, &serviceProviderGUID ); + HeapFree( GetProcessHeap(), 0, lpWGUIDString ); + /* FIXME: Have I got a memory leak on the serviceProviderGUID? */ + + /* Determine if this is the Service Provider that the user asked for */ + if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) ) + { + continue; + } + + /* Save the name of the SP or LP */ + lpSpData->lpszName = HEAP_strdupAtoW( GetProcessHeap(), 0, subKeyName ); + + sizeOfReturnBuffer = 255; + + /* Get dwReserved1 */ + if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey, + NULL, &returnType, returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR(": missing dwReserved1 registry data members\n") ; + continue; + } + + lpSpData->dwReserved1 = GET_DWORD( returnBuffer ); + + sizeOfReturnBuffer = 255; + + /* Get dwReserved2 */ + if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey, + NULL, &returnType, returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR(": missing dwReserved1 registry data members\n") ; + continue; + } + + lpSpData->dwReserved2 = GET_DWORD( returnBuffer ); + + + sizeOfReturnBuffer = 255; + + /* Get the path for this service provider */ + if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey, + NULL, NULL, returnBuffer, + &sizeOfReturnBuffer ) ) != ERROR_SUCCESS ) + { + ERR(": missing PATH registry data members: 0x%08lx\n", dwTemp ); + continue; + } + + return LoadLibraryA( returnBuffer ); + } + } + + return 0; +} + static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags ) { HMODULE hServiceProvider; - /*DWORD dwReturnValue; */ - typedef DWORD (WINAPI *SP_SPInit)(LPVOID, LPVOID, LPVOID ); /* FIXME: How many arguments? */ - SP_SPInit SPInit; + HRESULT hr; + LPDPSP_SPINIT SPInit; + GUID guidSP; + DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */ ICOM_THIS(IDirectPlay3Impl,iface); - FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpConnection, dwFlags ); + TRACE("(%p)->(%p,0x%08lx)\n", This, lpConnection, dwFlags ); if( dwFlags != 0 ) { return DPERR_INVALIDFLAGS; } - if( This->dp3->bConnectionInitialized == TRUE ) + if( This->dp2->bConnectionInitialized == TRUE ) { return DPERR_ALREADYINITIALIZED; } - /* Parse lpConnection as a compound address for the service provider */ - /* Take service provider GUID and find the path to it */ + /* Find out what the requested SP is and how large this buffer is */ + hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection, + dwAddrSize, &guidSP ); - /* FIXME: Hard coded to only load the tcp/ip service provider for now... */ - hServiceProvider = LoadLibraryA( "dpwsockx.dll" ); + if( FAILED(hr) ) + { + ERR( "Invalid compound address?\n" ); + return DPERR_UNAVAILABLE; + } + + /* Initialize what we can of the Service Provider required information. + * The rest will be done in DP_LoadSP + */ + This->dp2->spData.lpAddress = lpConnection; + This->dp2->spData.dwAddressSize = dwAddrSize; + This->dp2->spData.lpGuid = &guidSP; + + /* Load the service provider */ + hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData ); if( hServiceProvider == 0 ) { @@ -2895,23 +3860,33 @@ static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection } /* Initialize the service provider by calling SPInit */ - SPInit = (SP_SPInit)GetProcAddress( hServiceProvider, "SPInit" ); + SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" ); if( SPInit == NULL ) { ERR( "Service provider doesn't provide SPInit interface?\n" ); + FreeLibrary( hServiceProvider ); + return DPERR_UNAVAILABLE; } -#if 0 /* NOTE: This will crash until I know what parameters/interface this has */ - /* FIXME: Take a guess that we just pass the compound address to the SP */ - /* Hmmm...how to say which parameters need to be gotten from the SP. They must - come from the compound address, but how do we communicate what's required? */ - dwReturnValue = (*SPInit)( lpConnection, NULL, NULL ); -#endif + /* The first parameter is a pointer to memory which is written to... */ + + TRACE( "Calling SPInit\n" ); + hr = (*SPInit)( &This->dp2->spData ); + + if( FAILED(hr) ) + { + ERR( "SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) ); + FreeLibrary( hServiceProvider ); + return hr; + } /* This interface is now initialized */ - This->dp3->bConnectionInitialized = TRUE; + This->dp2->bConnectionInitialized = TRUE; + + /* Store the handle of the module so that we can unload it later */ + This->dp2->hServiceProvider = hServiceProvider; return DP_OK; } @@ -2929,7 +3904,7 @@ static HRESULT WINAPI DirectPlay3AImpl_SecureOpen LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials ) { ICOM_THIS(IDirectPlay2Impl,iface); /* Yes a dp 2 interface */ - return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials ); + return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE ); } static HRESULT WINAPI DirectPlay3WImpl_SecureOpen @@ -2937,7 +3912,7 @@ static HRESULT WINAPI DirectPlay3WImpl_SecureOpen LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials ) { ICOM_THIS(IDirectPlay2Impl,iface); /* Yes a dp 2 interface */ - return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials ); + return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE ); } static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage @@ -3004,31 +3979,35 @@ static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags return DP_OK; } -static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent - ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup ) +static HRESULT WINAPI DP_IF_GetGroupParent + ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup, + BOOL bAnsi ) { - lpGroupList lpGList; + lpGroupData lpGData; - ICOM_THIS(IDirectPlay3AImpl,iface); + TRACE("(%p)->(0x%08lx,%p,%u)\n", This, idGroup, lpidGroup, bAnsi ); - TRACE("(%p)->(0x%08lx,%p)\n", This, idGroup, lpidGroup ); - - if( ( lpGList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL ) + if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL ) { return DPERR_INVALIDGROUP; } - *lpidGroup = lpGList->lpGData->dpid; + *lpidGroup = lpGData->dpid; return DP_OK; } +static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent + ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup ) +{ + ICOM_THIS(IDirectPlay3Impl,iface); + return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE ); +} static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup ) { ICOM_THIS(IDirectPlay3Impl,iface); - FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroup ); - return DP_OK; + return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE ); } static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount @@ -3095,68 +4074,324 @@ static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner return DP_OK; } -static HRESULT WINAPI DirectPlay4AImpl_SendEx - ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout, LPVOID lpContext, LPDWORD lpdwMsgID ) +static HRESULT WINAPI DP_SendEx + ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout, + LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi ) { - ICOM_THIS(IDirectPlay4Impl,iface); - FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx,0x%08lx,0x%08lx,%p,%p): stub\n", This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority, dwTimeout, lpContext, lpdwMsgID ); - return DP_OK; + lpPlayerList lpPList; + lpGroupData lpGData; + BOOL bValidDestination = FALSE; + + FIXME( "(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx,0x%08lx,0x%08lx,%p,%p,%u)" + ": stub\n", + This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority, + dwTimeout, lpContext, lpdwMsgID, bAnsi ); + + /* FIXME: Add parameter checking */ + /* FIXME: First call to this needs to aquire a message id which will be + * used for multiple sends + */ + + /* NOTE: Can't send messages to yourself - this will be trapped in receive */ + + /* Verify that the message is being sent from a valid local player. The + * from player may be anonymous DPID_UNKNOWN + */ + if( idFrom != DPID_UNKNOWN ) + { + if( ( lpPList = DP_FindPlayer( This, idFrom ) ) == NULL ) + { + WARN( "INFO: Invalid from player 0x%08lx\n", idFrom ); + return DPERR_INVALIDPLAYER; + } + } + + /* Verify that the message is being sent to a valid player, group or to + * everyone. If it's valid, send it to those players. + */ + if( idTo == DPID_ALLPLAYERS ) + { + bValidDestination = TRUE; + + /* See if SP has the ability to multicast. If so, use it */ + if( This->dp2->spData.lpCB->SendToGroupEx ) + { + FIXME( "Use group sendex to group 0\n" ); + } + else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */ + { + FIXME( "Use obsolete group send to group 0\n" ); + } + else /* No multicast, multiplicate */ + { + /* Send to all players we know about */ + FIXME( "Send to all players using EnumPlayersInGroup\n" ); + } + } + + if( ( !bValidDestination ) && + ( DP_FindPlayer( This, idTo ) != NULL ) + ) + { + bValidDestination = TRUE; + + /* Have the servie provider send this message */ + /* FIXME: Could optimize for local interface sends */ + return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority, + dwTimeout, lpContext, lpdwMsgID ); + } + + if( ( !bValidDestination ) && + ( ( lpGData = DP_FindAnyGroup( This, idTo ) ) != NULL ) + ) + { + bValidDestination = TRUE; + + /* See if SP has the ability to multicast. If so, use it */ + if( This->dp2->spData.lpCB->SendToGroupEx ) + { + FIXME( "Use group sendex\n" ); + } + else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */ + { + FIXME( "Use obsolete group send to group\n" ); + } + else /* No multicast, multiplicate */ + { + FIXME( "Send to all players using EnumPlayersInGroup\n" ); + } + } + + if( !bValidDestination ) + { + return DPERR_INVALIDPLAYER; + } + else + { + /* FIXME: Should return what the send returned */ + return DP_OK; + } +} + + +static HRESULT WINAPI DirectPlay4AImpl_SendEx + ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout, + LPVOID lpContext, LPDWORD lpdwMsgID ) +{ + ICOM_THIS(IDirectPlay2Impl,iface); /* yes downcast to 2 */ + return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize, + dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE ); } static HRESULT WINAPI DirectPlay4WImpl_SendEx - ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout, LPVOID lpContext, LPDWORD lpdwMsgID ) + ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout, + LPVOID lpContext, LPDWORD lpdwMsgID ) { - ICOM_THIS(IDirectPlay4Impl,iface); - FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx,0x%08lx,0x%08lx,%p,%p): stub\n", This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority, dwTimeout, lpContext, lpdwMsgID ); + ICOM_THIS(IDirectPlay2Impl,iface); /* yes downcast to 2 */ + return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize, + dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE ); +} + +static HRESULT WINAPI DP_SP_SendEx + ( IDirectPlay2Impl* This, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout, + LPVOID lpContext, LPDWORD lpdwMsgID ) +{ + LPDPMSG lpMElem; + + FIXME( ": stub - wont work for multi process\n" ); + + /* FIXME: Need to send the passed message inside another message type + * I think. System message - but what is the format? + */ + + /* OK. Let's run a nasty hack to bypass the fact that we don't yet know + how to initialize the service provider. The hack will place the message + to be sent automatically into the send queue. There will + be nothing put into the send queue. In reality we should be calling + the service provider and only putting things into the send queue if + the service provider can't immediately accept/send it. + NOTE: Two hacks are provided. The first is only for a single process, + the second is a start towards a allowing sharing across the whole + computer (it requires some way of signalling that there's a message + available). + */ + +#ifdef SP_MULTIPROCESS_SEND_HACK + lpMElem = (LPDPMSG)DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, + sizeof( *lpMElem ) ); + lpMElem->msg = (DPMSG_GENERIC*)DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, + dwDataSize ); +#else + lpMElem = (LPDPMSG)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *lpMElem ) ); + lpMElem->msg = (DPMSG_GENERIC*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + dwDataSize ); +#endif + + CopyMemory( lpMElem->msg, lpData, dwDataSize ); + + DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs ); + return DP_OK; } +static HRESULT WINAPI DP_IF_GetMessageQueue + ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags, + LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi ) +{ + HRESULT hr = DP_OK; + + FIXME( "(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,%p,%u): semi stub\n", + This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi ); + + /* FIXME: Do we need to do idFrom and idTo sanity checking here? */ + /* FIXME: What about sends which are not immediate? */ + + if( This->dp2->spData.lpCB->GetMessageQueue ) + { + DPSP_GETMESSAGEQUEUEDATA data; + + FIXME( "Calling SP GetMessageQueue - is it right?\n" ); + + /* FIXME: None of this is documented :( */ + + data.lpISP = This->dp2->spData.lpISP; + data.dwFlags = dwFlags; + data.idFrom = idFrom; + data.idTo = idTo; + data.lpdwNumMsgs = lpdwNumMsgs; + data.lpdwNumBytes = lpdwNumBytes; + + hr = (This->dp2->spData.lpCB->GetMessageQueue)( &data ); + } + else + { + FIXME( "No SP for GetMessageQueue - fake some data\n" ); + } + + return hr; +} + static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue - ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes ) + ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags, + LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes ) { ICOM_THIS(IDirectPlay4Impl,iface); - FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,%p): stub\n", This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes ); - return DP_OK; + return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs, + lpdwNumBytes, TRUE ); } static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue - ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes ) + ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags, + LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes ) { ICOM_THIS(IDirectPlay4Impl,iface); - FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,%p): stub\n", This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes ); - return DP_OK; + return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs, + lpdwNumBytes, FALSE ); +} + +static HRESULT WINAPI DP_IF_CancelMessage + ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags, + DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi ) +{ + HRESULT hr = DP_OK; + + FIXME( "(%p)->(0x%08lx,0x%08lx,%u): semi stub\n", + This, dwMsgID, dwFlags, bAnsi ); + + if( This->dp2->spData.lpCB->Cancel ) + { + DPSP_CANCELDATA data; + + TRACE( "Calling SP Cancel\n" ); + + /* FIXME: Undocumented callback */ + + data.lpISP = This->dp2->spData.lpISP; + data.dwFlags = dwFlags; + data.lprglpvSPMsgID = NULL; + data.cSPMsgID = dwMsgID; + data.dwMinPriority = dwMinPriority; + data.dwMaxPriority = dwMaxPriority; + + hr = (This->dp2->spData.lpCB->Cancel)( &data ); + } + else + { + FIXME( "SP doesn't implement Cancel\n" ); + } + + return hr; } static HRESULT WINAPI DirectPlay4AImpl_CancelMessage ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags ) { ICOM_THIS(IDirectPlay4Impl,iface); - FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwMsgID, dwFlags ); - return DP_OK; + + if( dwFlags != 0 ) + { + return DPERR_INVALIDFLAGS; + } + + if( dwMsgID == 0 ) + { + dwFlags |= DPCANCELSEND_ALL; + } + + return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE ); } static HRESULT WINAPI DirectPlay4WImpl_CancelMessage ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags ) { ICOM_THIS(IDirectPlay4Impl,iface); - FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwMsgID, dwFlags ); - return DP_OK; + + if( dwFlags != 0 ) + { + return DPERR_INVALIDFLAGS; + } + + if( dwMsgID == 0 ) + { + dwFlags |= DPCANCELSEND_ALL; + } + + return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE ); } static HRESULT WINAPI DirectPlay4AImpl_CancelPriority - ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority, DWORD dwFlags ) + ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority, + DWORD dwFlags ) { ICOM_THIS(IDirectPlay4Impl,iface); - FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx): stub\n", This, dwMinPriority, dwMaxPriority, dwFlags ); - return DP_OK; + + if( dwFlags != 0 ) + { + return DPERR_INVALIDFLAGS; + } + + return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority, + dwMaxPriority, TRUE ); } static HRESULT WINAPI DirectPlay4WImpl_CancelPriority - ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority, DWORD dwFlags ) + ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority, + DWORD dwFlags ) { ICOM_THIS(IDirectPlay4Impl,iface); - FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx): stub\n", This, dwMinPriority, dwMaxPriority, dwFlags ); - return DP_OK; + + if( dwFlags != 0 ) + { + return DPERR_INVALIDFLAGS; + } + + return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority, + dwMaxPriority, FALSE ); } /* Note: Hack so we can reuse the old functions without compiler warnings */ @@ -3169,9 +4404,9 @@ static HRESULT WINAPI DirectPlay4WImpl_CancelPriority static ICOM_VTABLE(IDirectPlay2) directPlay2WVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - DirectPlay2W_QueryInterface, - XCAST(AddRef)DirectPlay2AImpl_AddRef, - XCAST(Release)DirectPlay2AImpl_Release, + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, DirectPlay2WImpl_AddPlayerToGroup, DirectPlay2WImpl_Close, @@ -3215,9 +4450,9 @@ static ICOM_VTABLE(IDirectPlay2) directPlay2WVT = static ICOM_VTABLE(IDirectPlay2) directPlay2AVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - DirectPlay2A_QueryInterface, - XCAST(AddRef)DirectPlay2AImpl_AddRef, - XCAST(Release)DirectPlay2AImpl_Release, + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, DirectPlay2AImpl_AddPlayerToGroup, DirectPlay2AImpl_Close, @@ -3262,9 +4497,9 @@ static ICOM_VTABLE(IDirectPlay2) directPlay2AVT = static ICOM_VTABLE(IDirectPlay3) directPlay3AVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - DirectPlay3AImpl_QueryInterface, - XCAST(AddRef)DirectPlay2AImpl_AddRef, - XCAST(Release)DirectPlay2AImpl_Release, + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup, XCAST(Close)DirectPlay2AImpl_Close, @@ -3323,9 +4558,9 @@ static ICOM_VTABLE(IDirectPlay3) directPlay3AVT = static ICOM_VTABLE(IDirectPlay3) directPlay3WVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - DirectPlay3WImpl_QueryInterface, - XCAST(AddRef)DirectPlay2AImpl_AddRef, - XCAST(Release)DirectPlay2AImpl_Release, + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup, XCAST(Close)DirectPlay2WImpl_Close, @@ -3384,9 +4619,9 @@ static ICOM_VTABLE(IDirectPlay3) directPlay3WVT = static ICOM_VTABLE(IDirectPlay4) directPlay4WVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - DirectPlay4WImpl_QueryInterface, - XCAST(AddRef)DirectPlay2AImpl_AddRef, - XCAST(Release)DirectPlay2AImpl_Release, + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup, XCAST(Close)DirectPlay2WImpl_Close, @@ -3453,9 +4688,9 @@ static ICOM_VTABLE(IDirectPlay4) directPlay4WVT = static ICOM_VTABLE(IDirectPlay4) directPlay4AVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - DirectPlay4AImpl_QueryInterface, - XCAST(AddRef)DirectPlay2AImpl_AddRef, - XCAST(Release)DirectPlay2AImpl_Release, + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup, XCAST(Close)DirectPlay2AImpl_Close, @@ -3658,6 +4893,40 @@ HRESULT WINAPI DirectPlayEnumerateW( LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID } +typedef struct tagCreateEnum +{ + LPVOID lpConn; + LPCGUID lpGuid; +} CreateEnumData, *lpCreateEnumData; + +/* Find and copy the matching connection for the SP guid */ +BOOL CALLBACK cbDPCreateEnumConnections( + LPCGUID lpguidSP, + LPVOID lpConnection, + DWORD dwConnectionSize, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext) +{ + lpCreateEnumData lpData = (lpCreateEnumData)lpContext; + + if( IsEqualGUID( lpguidSP, lpData->lpGuid ) ) + { + TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) ); + + lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + dwConnectionSize ); + CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize ); + + /* Found the record that we were looking for */ + return FALSE; + } + + /* Haven't found what were looking for yet */ + return TRUE; +} + + /*************************************************************************** * DirectPlayCreate (DPLAYX.1) (DPLAY.1) * @@ -3665,6 +4934,10 @@ HRESULT WINAPI DirectPlayEnumerateW( LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID HRESULT WINAPI DirectPlayCreate ( LPGUID lpGUID, LPDIRECTPLAY2 *lplpDP, IUnknown *pUnk) { + HRESULT hr; + LPDIRECTPLAY3A lpDP3A; + CreateEnumData cbData; + TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk ); if( pUnk != NULL ) @@ -3675,7 +4948,7 @@ HRESULT WINAPI DirectPlayCreate /* Create an IDirectPlay object. We don't support that so we'll cheat and give them an IDirectPlay2A object and hope that doesn't cause problems */ - if( directPlay_QueryInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK ) + if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK ) { return DPERR_UNAVAILABLE; } @@ -3683,28 +4956,50 @@ HRESULT WINAPI DirectPlayCreate if( IsEqualGUID( &GUID_NULL, lpGUID ) ) { /* The GUID_NULL means don't bind a service provider. Just return the - interface */ + interface as is */ return DP_OK; } + /* Bind the desired service provider since lpGUID is non NULL */ + TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) ); - /* Bind the desired service provider */ - if( ( IsEqualGUID( lpGUID, &DPSPGUID_MODEM ) ) || - ( IsEqualGUID( lpGUID, &DPSPGUID_SERIAL ) ) || - ( IsEqualGUID( lpGUID, &DPSPGUID_TCPIP ) ) || - ( IsEqualGUID( lpGUID, &DPSPGUID_IPX ) ) - ) + /* We're going to use a DP3 interface */ + hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A, + (LPVOID*)&lpDP3A ); + if( FAILED(hr) ) { - FIXME( "Service provider binding not supported yet\n" ); - IDirectPlayX_Release( *lplpDP ); - *lplpDP = NULL; - return DPERR_INVALIDPARAMS; + ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) ); + return hr; } - ERR( "unknown Service Provider %s\n", debugstr_guid(lpGUID) ); + cbData.lpConn = NULL; + cbData.lpGuid = lpGUID; - IDirectPlayX_Release( *lplpDP ); - *lplpDP = NULL; + /* We were given a service provider, find info about it... */ + hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections, + &cbData, DPCONNECTION_DIRECTPLAY ); + if( ( FAILED(hr) ) || + ( cbData.lpConn == NULL ) + ) + { + ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) ); + IDirectPlayX_Release( lpDP3A ); + return DPERR_UNAVAILABLE; + } - return DPERR_INVALIDPARAMS; + /* Initialize the service provider */ + hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 ); + if( FAILED(hr) ) + { + ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) ); + HeapFree( GetProcessHeap(), 0, cbData.lpConn ); + IDirectPlayX_Release( lpDP3A ); + return hr; + } + + /* Release our version of the interface now that we're done with it */ + IDirectPlayX_Release( lpDP3A ); + HeapFree( GetProcessHeap(), 0, cbData.lpConn ); + + return DP_OK; } diff --git a/dlls/dplayx/dplay_global.h b/dlls/dplayx/dplay_global.h new file mode 100644 index 00000000000..8547568c6cd --- /dev/null +++ b/dlls/dplayx/dplay_global.h @@ -0,0 +1,185 @@ +#ifndef __WINE_DPLAY_GLOBAL_INCLUDED +#define __WINE_DPLAY_GLOBAL_INCLUDED + +#include "dplaysp.h" +#include "dplayx_queue.h" + +extern HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, + LPCVOID lpAddress, DWORD dwAddressSize, + LPVOID lpContext ); + +extern DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi ); + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +typedef struct IDirectPlay2Impl IDirectPlay2AImpl; +typedef struct IDirectPlay2Impl IDirectPlay2Impl; +typedef struct IDirectPlay3Impl IDirectPlay3AImpl; +typedef struct IDirectPlay3Impl IDirectPlay3Impl; +typedef struct IDirectPlay4Impl IDirectPlay4AImpl; +typedef struct IDirectPlay4Impl IDirectPlay4Impl; + +typedef struct tagDirectPlayIUnknownData +{ + ULONG ulObjRef; + CRITICAL_SECTION DP_lock; +} DirectPlayIUnknownData; + +typedef struct tagEnumSessionAsyncCallbackData +{ + LPSPINITDATA lpSpData; + GUID requestGuid; + DWORD dwEnumSessionFlags; + DWORD dwTimeout; + HANDLE hSuicideRequest; +} EnumSessionAsyncCallbackData; + +struct PlayerData +{ + /* Individual player information */ + DPID dpid; + + DPNAME name; + HANDLE hEvent; + + /* View of local data */ + LPVOID lpLocalData; + DWORD dwLocalDataSize; + + /* View of remote data */ + LPVOID lpRemoteData; + DWORD dwRemoteDataSize; + + DWORD dwFlags; /* Special remarks about the type of player */ +}; +typedef struct PlayerData* lpPlayerData; + +struct PlayerList +{ + DPQ_ENTRY(PlayerList) players; + + lpPlayerData lpPData; +}; +typedef struct PlayerList* lpPlayerList; + +struct GroupData +{ + /* Internal information */ + DPID parent; /* If parent == 0 it's a top level group */ + + DPQ_HEAD(GroupList) groups; /* A group has [0..n] groups */ + DPQ_HEAD(PlayerList) players; /* A group has [0..n] players */ + + DPID idGroupOwner; /* ID of player who owns the group */ + + DWORD dwFlags; /* Flags describing anything special about the group */ + + DPID dpid; + DPNAME name; + + /* View of local data */ + LPVOID lpLocalData; + DWORD dwLocalDataSize; + + /* View of remote data */ + LPVOID lpRemoteData; + DWORD dwRemoteDataSize; +}; +typedef struct GroupData GroupData; +typedef struct GroupData* lpGroupData; + +struct GroupList +{ + DPQ_ENTRY(GroupList) groups; + + lpGroupData lpGData; +}; +typedef struct GroupList* lpGroupList; + +struct DPMSG +{ + DPQ_ENTRY( DPMSG ) msgs; + DPMSG_GENERIC* msg; +}; +typedef struct DPMSG* LPDPMSG; + +/* Contains all dp1 and dp2 data members */ +typedef struct tagDirectPlay2Data +{ + BOOL bConnectionOpen; + + /* For async EnumSessions requests */ + HANDLE hEnumSessionThread; + HANDLE hKillEnumSessionThreadEvent; + + LPVOID lpNameServerData; /* DPlay interface doesn't know contents */ + + BOOL bHostInterface; /* Did this interface create the session */ + +#if 0 + DPQ_HEAD(PlayerList) players; /* All players w/ interface */ + DPQ_HEAD(GroupList) groups; /* All main groups w/ interface */ +#else + lpGroupData lpSysGroup; /* System group with _everything_ in it */ +#endif + + LPDPSESSIONDESC2 lpSessionDesc; + + /* I/O Msg queues */ + DPQ_HEAD( DPMSG ) receiveMsgs; /* Msg receive queue */ + DPQ_HEAD( DPMSG ) sendMsgs; /* Msg send pending queue */ + + /* Information about the service provider active on this connection */ + SPINITDATA spData; + + /* Our service provider */ + HMODULE hServiceProvider; + + BOOL bConnectionInitialized; +} DirectPlay2Data; + +typedef struct tagDirectPlay3Data +{ + BOOL dummy; +} DirectPlay3Data; +typedef struct tagDirectPlay4Data +{ + BOOL dummy; +} DirectPlay4Data; + +#define DP_IMPL_FIELDS \ + ULONG ulInterfaceRef; \ + DirectPlayIUnknownData* unk; \ + DirectPlay2Data* dp2; \ + DirectPlay3Data* dp3; \ + DirectPlay4Data* dp4; + +struct IDirectPlay2Impl +{ + ICOM_VFIELD(IDirectPlay2); + DP_IMPL_FIELDS +}; + +struct IDirectPlay3Impl +{ + ICOM_VFIELD(IDirectPlay3); + DP_IMPL_FIELDS +}; + +struct IDirectPlay4Impl +{ + ICOM_VFIELD(IDirectPlay4); + DP_IMPL_FIELDS +}; + +/* Forward declarations of virtual tables */ +extern ICOM_VTABLE(IDirectPlay2) directPlay2AVT; +extern ICOM_VTABLE(IDirectPlay3) directPlay3AVT; +extern ICOM_VTABLE(IDirectPlay4) directPlay4AVT; + +extern ICOM_VTABLE(IDirectPlay2) directPlay2WVT; +extern ICOM_VTABLE(IDirectPlay3) directPlay3WVT; +extern ICOM_VTABLE(IDirectPlay4) directPlay4WVT; + +#endif /* __WINE_DPLAY_GLOBAL_INCLUDED */ diff --git a/dlls/dplayx/dplaysp.c b/dlls/dplayx/dplaysp.c new file mode 100644 index 00000000000..98962de1ea5 --- /dev/null +++ b/dlls/dplayx/dplaysp.c @@ -0,0 +1,880 @@ +/* This contains the implementation of the interface Service + * Providers require to communicate with Direct Play + * + * Copyright 2000 Peter Hunnisett + */ + +#include "heap.h" +#include "winerror.h" +#include "debugtools.h" + +#include "dpinit.h" +#include "dplaysp.h" +#include "dplay_global.h" +#include "name_server.h" +#include "dplayx_messages.h" + +#include "dplayx_global.h" /* FIXME: For global hack */ + +/* FIXME: Need to add interface locking inside procedures */ + +DEFAULT_DEBUG_CHANNEL(dplay); + +/* Prototypes */ +static BOOL DPSP_CreateIUnknown( LPVOID lpSP ); +static BOOL DPSP_DestroyIUnknown( LPVOID lpSP ); +static BOOL DPSP_CreateDirectPlaySP( LPVOID lpSP, IDirectPlay2Impl* dp ); +static BOOL DPSP_DestroyDirectPlaySP( LPVOID lpSP ); + + +/* Predefine the interface */ +typedef struct IDirectPlaySPImpl IDirectPlaySPImpl; + +typedef struct tagDirectPlaySPIUnknownData +{ + ULONG ulObjRef; + CRITICAL_SECTION DPSP_lock; +} DirectPlaySPIUnknownData; + +typedef struct tagDirectPlaySPData +{ + LPVOID lpSpRemoteData; + DWORD dwSpRemoteDataSize; /* Size of data pointed to by lpSpRemoteData */ + + LPVOID lpSpLocalData; + DWORD dwSpLocalDataSize; /* Size of data pointed to by lpSpLocalData */ + + IDirectPlay2Impl* dplay; /* FIXME: This should perhaps be iface not impl */ + + LPVOID lpPlayerData; /* FIXME: Need to figure out how this actually behaves */ + DWORD dwPlayerDataSize; +} DirectPlaySPData; + +#define DPSP_IMPL_FIELDS \ + ULONG ulInterfaceRef; \ + DirectPlaySPIUnknownData* unk; \ + DirectPlaySPData* sp; + +struct IDirectPlaySPImpl +{ + ICOM_VFIELD(IDirectPlaySP); + DPSP_IMPL_FIELDS +}; + +/* Forward declaration of virtual tables */ +static ICOM_VTABLE(IDirectPlaySP) directPlaySPVT; + + + +/* Create the SP interface */ +extern +HRESULT DPSP_CreateInterface( REFIID riid, LPVOID* ppvObj, IDirectPlay2Impl* dp ) +{ + TRACE( " for %s\n", debugstr_guid( riid ) ); + + *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( IDirectPlaySPImpl ) ); + + if( *ppvObj == NULL ) + { + return DPERR_OUTOFMEMORY; + } + + if( IsEqualGUID( &IID_IDirectPlaySP, riid ) ) + { + ICOM_THIS(IDirectPlaySPImpl,*ppvObj); + ICOM_VTBL(This) = &directPlaySPVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + return E_NOINTERFACE; + } + + /* Initialize it */ + if( DPSP_CreateIUnknown( *ppvObj ) && + DPSP_CreateDirectPlaySP( *ppvObj, dp ) + ) + { + IDirectPlaySP_AddRef( (LPDIRECTPLAYSP)*ppvObj ); + return S_OK; + } + + /* Initialize failed, destroy it */ + DPSP_DestroyDirectPlaySP( *ppvObj ); + DPSP_DestroyIUnknown( *ppvObj ); + + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + return DPERR_NOMEMORY; +} + +static BOOL DPSP_CreateIUnknown( LPVOID lpSP ) +{ + ICOM_THIS(IDirectPlaySPImpl,lpSP); + + This->unk = (DirectPlaySPIUnknownData*)HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof( *(This->unk) ) ); + + if ( This->unk == NULL ) + { + return FALSE; + } + + InitializeCriticalSection( &This->unk->DPSP_lock ); + + return TRUE; +} + +static BOOL DPSP_DestroyIUnknown( LPVOID lpSP ) +{ + ICOM_THIS(IDirectPlaySPImpl,lpSP); + + DeleteCriticalSection( &This->unk->DPSP_lock ); + HeapFree( GetProcessHeap(), 0, This->unk ); + + return TRUE; +} + + +static BOOL DPSP_CreateDirectPlaySP( LPVOID lpSP, IDirectPlay2Impl* dp ) +{ + ICOM_THIS(IDirectPlaySPImpl,lpSP); + + This->sp = (DirectPlaySPData*)HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof( *(This->sp) ) ); + + if ( This->sp == NULL ) + { + return FALSE; + } + + This->sp->dplay = dp; + + /* Normally we should be keeping a reference, but since only the dplay + * interface that created us can destroy us, we do not keep a reference + * to it (ie we'd be stuck with always having one reference to the dplay + * object, and hence us, around). + * NOTE: The dp object does reference count us. + */ + /* IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp ); */ + + return TRUE; +} + +static BOOL DPSP_DestroyDirectPlaySP( LPVOID lpSP ) +{ + ICOM_THIS(IDirectPlaySPImpl,lpSP); + + /* Normally we should be keeping a reference, but since only the dplay + * interface that created us can destroy us, we do not keep a reference + * to it (ie we'd be stuck with always having one reference to the dplay + * object, and hence us, around). + * NOTE: The dp object does reference count us. + */ + /*IDirectPlayX_Release( (LPDIRECTPLAY2)This->sp->dplay ); */ + + HeapFree( GetProcessHeap(), 0, This->sp->lpSpRemoteData ); + HeapFree( GetProcessHeap(), 0, This->sp->lpSpLocalData ); + + /* FIXME: Need to delete player queue */ + + HeapFree( GetProcessHeap(), 0, This->sp ); + return TRUE; +} + +/* Interface implementation */ + +static HRESULT WINAPI DPSP_QueryInterface +( LPDIRECTPLAYSP iface, + REFIID riid, + LPVOID* ppvObj ) +{ + ICOM_THIS(IDirectPlaySPImpl,iface); + TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj ); + + *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( IDirectPlaySPImpl ) ); + + if( *ppvObj == NULL ) + { + return DPERR_OUTOFMEMORY; + } + + CopyMemory( *ppvObj, iface, sizeof( IDirectPlaySPImpl ) ); + (*(IDirectPlaySPImpl**)ppvObj)->ulInterfaceRef = 0; + + if( IsEqualGUID( &IID_IDirectPlaySP, riid ) ) + { + ICOM_THIS(IDirectPlaySPImpl,*ppvObj); + ICOM_VTBL(This) = &directPlaySPVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + return E_NOINTERFACE; + } + + IDirectPlaySP_AddRef( (LPDIRECTPLAYSP)*ppvObj ); + + return S_OK; +} + +static ULONG WINAPI DPSP_AddRef +( LPDIRECTPLAYSP iface ) +{ + ULONG ulInterfaceRefCount, ulObjRefCount; + ICOM_THIS(IDirectPlaySPImpl,iface); + + ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef ); + ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef ); + + TRACE( "ref count incremented to %lu:%lu for %p\n", + ulInterfaceRefCount, ulObjRefCount, This ); + + return ulObjRefCount; +} + +static ULONG WINAPI DPSP_Release +( LPDIRECTPLAYSP iface ) +{ + ULONG ulInterfaceRefCount, ulObjRefCount; + ICOM_THIS(IDirectPlaySPImpl,iface); + + ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef ); + ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef ); + + TRACE( "ref count decremented to %lu:%lu for %p\n", + ulInterfaceRefCount, ulObjRefCount, This ); + + /* Deallocate if this is the last reference to the object */ + if( ulObjRefCount == 0 ) + { + DPSP_DestroyDirectPlaySP( This ); + DPSP_DestroyIUnknown( This ); + } + + if( ulInterfaceRefCount == 0 ) + { + HeapFree( GetProcessHeap(), 0, This ); + } + + return ulInterfaceRefCount; +} + +static HRESULT WINAPI IDirectPlaySPImpl_AddMRUEntry +( LPDIRECTPLAYSP iface, + LPCWSTR lpSection, + LPCWSTR lpKey, + LPCVOID lpData, + DWORD dwDataSize, + DWORD dwMaxEntries +) +{ + ICOM_THIS(IDirectPlaySPImpl,iface); + + FIXME( "(%p)->(%p,%p%p,0x%08lx,0x%08lx): stub\n", + This, lpSection, lpKey, lpData, dwDataSize, dwMaxEntries ); + + return DP_OK; +} + +static HRESULT WINAPI IDirectPlaySPImpl_CreateAddress +( LPDIRECTPLAYSP iface, + REFGUID guidSP, + REFGUID guidDataType, + LPCVOID lpData, + DWORD dwDataSize, + LPVOID lpAddress, + LPDWORD lpdwAddressSize +) +{ + ICOM_THIS(IDirectPlaySPImpl,iface); + + FIXME( "(%p)->(%s,%s,%p,0x%08lx,%p,%p): stub\n", + This, debugstr_guid(guidSP), debugstr_guid(guidDataType), + lpData, dwDataSize, lpAddress, lpdwAddressSize ); + + return DP_OK; +} + +static HRESULT WINAPI IDirectPlaySPImpl_EnumAddress +( LPDIRECTPLAYSP iface, + LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, + LPCVOID lpAddress, + DWORD dwAddressSize, + LPVOID lpContext +) +{ + ICOM_THIS(IDirectPlaySPImpl,iface); + + TRACE( "(%p)->(%p,%p,0x%08lx,%p)\n", + This, lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext ); + + DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext ); + + return DP_OK; +} + +static HRESULT WINAPI IDirectPlaySPImpl_EnumMRUEntries +( LPDIRECTPLAYSP iface, + LPCWSTR lpSection, + LPCWSTR lpKey, + LPENUMMRUCALLBACK lpEnumMRUCallback, + LPVOID lpContext +) +{ + ICOM_THIS(IDirectPlaySPImpl,iface); + + FIXME( "(%p)->(%p,%p,%p,%p,): stub\n", + This, lpSection, lpKey, lpEnumMRUCallback, lpContext ); + + return DP_OK; +} + +static HRESULT WINAPI IDirectPlaySPImpl_GetPlayerFlags +( LPDIRECTPLAYSP iface, + DPID idPlayer, + LPDWORD lpdwPlayerFlags +) +{ + ICOM_THIS(IDirectPlaySPImpl,iface); + + FIXME( "(%p)->(0x%08lx,%p): stub\n", + This, idPlayer, lpdwPlayerFlags ); + + return DP_OK; +} + +static HRESULT WINAPI IDirectPlaySPImpl_GetSPPlayerData +( LPDIRECTPLAYSP iface, + DPID idPlayer, + LPVOID* lplpData, + LPDWORD lpdwDataSize, + DWORD dwFlags +) +{ + ICOM_THIS(IDirectPlaySPImpl,iface); + + TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); + FIXME( "(%p)->(0x%08lx,%p,%p,0x%08lx): stub\n", + This, idPlayer, lplpData, lpdwDataSize, dwFlags ); + + *lplpData = This->sp->lpPlayerData; + *lpdwDataSize = This->sp->dwPlayerDataSize; + + return DP_OK; +} + +static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage +( LPDIRECTPLAYSP iface, + LPVOID lpMessageBody, + DWORD dwMessageBodySize, + LPVOID lpMessageHeader +) +{ + LPDPMSG_SENDENVELOPE lpMsg = (LPDPMSG_SENDENVELOPE)lpMessageBody; + HRESULT hr = DPERR_GENERIC; + + ICOM_THIS(IDirectPlaySPImpl,iface); + + TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); + FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n", + This, lpMessageBody, dwMessageBodySize, lpMessageHeader ); + + TRACE( "Incomming message has envelope of 0x%08lx, %u, %u\n", + lpMsg->dwMagic, lpMsg->wCommandId, lpMsg->wVersion ); + + if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG ) + { + FIXME( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic ); + } + + switch( lpMsg->wCommandId ) + { + case DPMSGCMD_ENUMSESSIONSREQUEST: + { + DPSP_REPLYDATA data; + + data.lpSPMessageHeader = lpMessageHeader; + data.idNameServer = 0; + data.lpISP = iface; + + NS_ReplyToEnumSessionsRequest( lpMessageBody, &data, This->sp->dplay ); + + hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data ); + + if( FAILED(hr) ) + { + ERR( "Reply failed 0x%08lx\n", hr ); + } + + break; + } + + case DPMSGCMD_ENUMSESSIONSREPLY: + { + NS_SetRemoteComputerAsNameServer( lpMessageHeader, + This->sp->dplay->dp2->spData.dwSPHeaderSize, + (LPDPMSG_ENUMSESSIONSREPLY)lpMessageBody, + This->sp->dplay->dp2->lpNameServerData ); + + /* No reply expected */ + + break; + } + default: + FIXME( "Unknown Command of %u\n", lpMsg->wCommandId ); + } + +#if 0 + HRESULT hr = DP_OK; + HANDLE hReceiveEvent = 0; + /* FIXME: Aquire some sort of interface lock */ + /* FIXME: Need some sort of context for this callback. Need to determine + * how this is actually done with the SP + */ + /* FIXME: Add in size checks for all messages to determine corrupt messages */ /* FIXME: Who needs to delete the message when done? */ + /* FIXME: Does this get invoked as soon as the message arrives, or as soon + * as it's removed from the queue (or peeked in queue?) + */ + switch( lpMsg->dwType ) + { + case DPSYS_CREATEPLAYERORGROUP: + { + LPDPMSG_CREATEPLAYERORGROUP msg = (LPDPMSG_CREATEPLAYERORGROUP)lpMsg; + + if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER ) + { + hr = DP_IF_CreatePlayer( This, lpMessageHeader, msg->dpId, + &msg->dpnName, 0, msg->lpData, + msg->dwDataSize, msg->dwFlags, ... ); + } + else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP ) + { + /* Group in group situation? */ + if( msg->dpIdParent == DPID_NOPARENT_GROUP ) + { + hr = DP_IF_CreateGroup( This, lpMessageHeader, msg->dpId, + &msg->dpnName, 0, msg->lpData, + msg->dwDataSize, msg->dwFlags, ... ); + } + else /* Group in Group */ + { + hr = DP_IF_CreateGroupInGroup( This, lpMessageHeader, msg->dpIdParent, + &msg->dpnName, 0, msg->lpData, + msg->dwDataSize, msg->dwFlags, ... ); + } + } + else /* Hmmm? */ + { + ERR( "Corrupt msg->dwPlayerType for DPSYS_CREATEPLAYERORGROUP\n" ); + return; + } + + break; + } + + case DPSYS_DESTROYPLAYERORGROUP: + { + LPDPMSG_DESTROYPLAYERORGROUP msg = (LPDPMSG_DESTROYPLAYERORGROUP)lpMsg; + + if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER ) + { + hr = DP_IF_DestroyPlayer( This, msg->dpId, ... ); + } + else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP ) + { + hr = DP_IF_DestroyGroup( This, msg->dpId, ... ); + } + else /* Hmmm? */ + { + ERR( "Corrupt msg->dwPlayerType for DPSYS_DESTROYPLAYERORGROUP\n" ); + return; + } + + break; + } + + case DPSYS_ADDPLAYERTOGROUP: + { + LPDPMSG_ADDPLAYERTOGROUP msg = (LPDPMSG_ADDPLAYERTOGROUP)lpMsg; + + hr = DP_IF_AddPlayerToGroup( This, msg->dpIdGroup, msg->dpIdPlayer, ... ); + break; + } + + case DPSYS_DELETEPLAYERFROMGROUP: + { + LPDPMSG_DELETEPLAYERFROMGROUP msg = (LPDPMSG_DELETEPLAYERFROMGROUP)lpMsg; + + hr = DP_IF_DeletePlayerFromGroup( This, msg->dpIdGroup, msg->dpIdPlayer, + ... ); + + break; + } + + case DPSYS_SESSIONLOST: + { + LPDPMSG_SESSIONLOST msg = (LPDPMSG_SESSIONLOST)lpMsg; + + FIXME( "DPSYS_SESSIONLOST not handled\n" ); + + break; + } + + case DPSYS_HOST: + { + LPDPMSG_HOST msg = (LPDPMSG_HOST)lpMsg; + + FIXME( "DPSYS_HOST not handled\n" ); + + break; + } + + case DPSYS_SETPLAYERORGROUPDATA: + { + LPDPMSG_SETPLAYERORGROUPDATA msg = (LPDPMSG_SETPLAYERORGROUPDATA)lpMsg; + + if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER ) + { + hr = DP_IF_SetPlayerData( This, msg->dpId, msg->lpData, msg->dwDataSize, DPSET_REMOTE, ... ); + } + else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP ) + { + hr = DP_IF_SetGroupData( This, msg->dpId, msg->lpData, msg->dwDataSize, + DPSET_REMOTE, ... ); + } + else /* Hmmm? */ + { + ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" ); + return; + } + + break; + } + + case DPSYS_SETPLAYERORGROUPNAME: + { + LPDPMSG_SETPLAYERORGROUPNAME msg = (LPDPMSG_SETPLAYERORGROUPNAME)lpMsg; + + if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER ) + { + hr = DP_IF_SetPlayerName( This, msg->dpId, msg->dpnName, ... ); + } + else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP ) + { + hr = DP_IF_SetGroupName( This, msg->dpId, msg->dpnName, ... ); + } + else /* Hmmm? */ + { + ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" ); + return; + } + + break; + } + + case DPSYS_SETSESSIONDESC; + { + LPDPMSG_SETSESSIONDESC msg = (LPDPMSG_SETSESSIONDESC)lpMsg; + + hr = DP_IF_SetSessionDesc( This, &msg->dpDesc ); + + break; + } + + case DPSYS_ADDGROUPTOGROUP: + { + LPDPMSG_ADDGROUPTOGROUP msg = (LPDPMSG_ADDGROUPTOGROUP)lpMsg; + + hr = DP_IF_AddGroupToGroup( This, msg->dpIdParentGroup, msg->dpIdGroup, + ... ); + + break; + } + + case DPSYS_DELETEGROUPFROMGROUP: + { + LPDPMSG_DELETEGROUPFROMGROUP msg = (LPDPMSG_DELETEGROUPFROMGROUP)lpMsg; + + hr = DP_IF_DeleteGroupFromGroup( This, msg->dpIdParentGroup, + msg->dpIdGroup, ... ); + + break; + } + + case DPSYS_SECUREMESSAGE: + { + LPDPMSG_SECUREMESSAGE msg = (LPDPMSG_SECUREMESSAGE)lpMsg; + + FIXME( "DPSYS_SECUREMESSAGE not implemented\n" ); + + break; + } + + case DPSYS_STARTSESSION: + { + LPDPMSG_STARTSESSION msg = (LPDPMSG_STARTSESSION)lpMsg; + + FIXME( "DPSYS_STARTSESSION not implemented\n" ); + + break; + } + + case DPSYS_CHAT: + { + LPDPMSG_CHAT msg = (LPDPMSG_CHAT)lpMsg; + + FIXME( "DPSYS_CHAT not implemeneted\n" ); + + break; + } + + case DPSYS_SETGROUPOWNER: + { + LPDPMSG_SETGROUPOWNER msg = (LPDPMSG_SETGROUPOWNER)lpMsg; + + FIXME( "DPSYS_SETGROUPOWNER not implemented\n" ); + + break; + } + + case DPSYS_SENDCOMPLETE: + { + LPDPMSG_SENDCOMPLETE msg = (LPDPMSG_SENDCOMPLETE)lpMsg; + + FIXME( "DPSYS_SENDCOMPLETE not implemented\n" ); + + break; + } + + default: + { + /* NOTE: This should be a user defined type. There is nothing that we + * need to do with it except queue it. + */ + TRACE( "Received user message type(?) 0x%08lx through SP.\n", + lpMsg->dwType ); + break; + } + } + + FIXME( "Queue message in the receive queue. Need some context data!\n" ); + + if( FAILED(hr) ) + { + ERR( "Unable to perform action for msg type 0x%08lx\n", lpMsg->dwType ); + } + /* If a receieve event was registered for this player, invoke it */ + if( hReceiveEvent ) + { + SetEvent( hReceiveEvent ); + } +#endif + + return hr; +} + +static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData +( LPDIRECTPLAYSP iface, + DPID idPlayer, + LPVOID lpData, + DWORD dwDataSize, + DWORD dwFlags +) +{ + ICOM_THIS(IDirectPlaySPImpl,iface); + + /* FIXME: I'm not sure if this stuff should be associated with the DPlay + * player lists. How else would this stuff get deleted? + */ + + TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); + FIXME( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx): stub\n", + This, idPlayer, lpData, dwDataSize, dwFlags ); + + This->sp->lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize ); + + This->sp->dwPlayerDataSize = dwDataSize; + CopyMemory( This->sp->lpPlayerData, lpData, dwDataSize ); + + return DP_OK; +} + +static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress +( LPDIRECTPLAYSP iface, + LPCDPCOMPOUNDADDRESSELEMENT lpElements, + DWORD dwElementCount, + LPVOID lpAddress, + LPDWORD lpdwAddressSize +) +{ + ICOM_THIS(IDirectPlaySPImpl,iface); + + FIXME( "(%p)->(%p,0x%08lx,%p,%p): stub\n", + This, lpElements, dwElementCount, lpAddress, lpdwAddressSize ); + + return DP_OK; +} + +static HRESULT WINAPI IDirectPlaySPImpl_GetSPData +( LPDIRECTPLAYSP iface, + LPVOID* lplpData, + LPDWORD lpdwDataSize, + DWORD dwFlags +) +{ + ICOM_THIS(IDirectPlaySPImpl,iface); + + TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); + TRACE( "(%p)->(%p,%p,0x%08lx)\n", + This, lplpData, lpdwDataSize, dwFlags ); + +#if 0 + /* This is what the documentation says... */ + if( dwFlags != 0 ) + { + return DPERR_INVALIDPARAMS; + } +#else + /* ... but most service providers call this with 1 */ + /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of + * thing? + */ + if( dwFlags != 0 ) + { + FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags ); + } +#endif + + /* Yes, we're supposed to return a pointer to the memory we have stored! */ + if( dwFlags == DPSET_REMOTE ) + { + *lpdwDataSize = This->sp->dwSpRemoteDataSize; + *lplpData = This->sp->lpSpRemoteData; + } + else if( dwFlags == DPSET_LOCAL ) + { + *lpdwDataSize = This->sp->dwSpLocalDataSize; + *lplpData = This->sp->lpSpLocalData; + } + + return DP_OK; +} + +static HRESULT WINAPI IDirectPlaySPImpl_SetSPData +( LPDIRECTPLAYSP iface, + LPVOID lpData, + DWORD dwDataSize, + DWORD dwFlags +) +{ + LPVOID lpSpData; + + ICOM_THIS(IDirectPlaySPImpl,iface); + + TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); + TRACE( "(%p)->(%p,0x%08lx,0x%08lx)\n", + This, lpData, dwDataSize, dwFlags ); + +#if 0 + /* This is what the documentation says... */ + if( dwFlags != 0 ) + { + return DPERR_INVALIDPARAMS; + } +#else + /* ... but most service providers call this with 1 */ + /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of + * thing? + */ + if( dwFlags != 0 ) + { + FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags ); + } +#endif + + if( dwFlags == DPSET_REMOTE ) + { + lpSpData = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, dwDataSize ); + } + else + { + lpSpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize ); + } + + CopyMemory( lpSpData, lpData, dwDataSize ); + + /* If we have data already allocated, free it and replace it */ + if( dwFlags == DPSET_REMOTE ) + { + /* FIXME: This doesn't strictly make sense as there is no means to share + * this shared data. Must be misinterpreting something... + */ + if( This->sp->lpSpRemoteData ) + { + DPLAYX_PrivHeapFree( This->sp->lpSpRemoteData ); + } + + /* NOTE: dwDataSize is also stored in the heap structure */ + This->sp->dwSpRemoteDataSize = dwDataSize; + This->sp->lpSpRemoteData = lpSpData; + } + else if ( dwFlags == DPSET_LOCAL ) + { + if( This->sp->lpSpLocalData ) + { + HeapFree( GetProcessHeap(), 0, This->sp->lpSpLocalData ); + } + + This->sp->lpSpLocalData = lpSpData; + This->sp->dwSpLocalDataSize = dwDataSize; + } + + return DP_OK; +} + +static VOID WINAPI IDirectPlaySPImpl_SendComplete +( LPDIRECTPLAYSP iface, + LPVOID unknownA, + DWORD unknownB +) +{ + ICOM_THIS(IDirectPlaySPImpl,iface); + + FIXME( "(%p)->(%p,0x%08lx): stub\n", + This, unknownA, unknownB ); +} + + +static struct ICOM_VTABLE(IDirectPlaySP) directPlaySPVT = +{ + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + + DPSP_QueryInterface, + DPSP_AddRef, + DPSP_Release, + + IDirectPlaySPImpl_AddMRUEntry, + IDirectPlaySPImpl_CreateAddress, + IDirectPlaySPImpl_EnumAddress, + IDirectPlaySPImpl_EnumMRUEntries, + IDirectPlaySPImpl_GetPlayerFlags, + IDirectPlaySPImpl_GetSPPlayerData, + IDirectPlaySPImpl_HandleMessage, + IDirectPlaySPImpl_SetSPPlayerData, + IDirectPlaySPImpl_CreateCompoundAddress, + IDirectPlaySPImpl_GetSPData, + IDirectPlaySPImpl_SetSPData, + IDirectPlaySPImpl_SendComplete +}; diff --git a/dlls/dplayx/dplaysp.h b/dlls/dplayx/dplaysp.h new file mode 100644 index 00000000000..c2028f07a57 --- /dev/null +++ b/dlls/dplayx/dplaysp.h @@ -0,0 +1,337 @@ +#ifndef __WINE_DIRECT_PLAY_SP_H +#define __WINE_DIRECT_PLAY_SP_H + +#include "dplay.h" +#include "dplobby.h" + +/* GUID for IDirectPlaySP {0C9F6360-CC61-11cf-ACEC-00AA006886E3} */ +DEFINE_GUID(IID_IDirectPlaySP, 0xc9f6360, 0xcc61, 0x11cf, 0xac, 0xec, 0x0, 0xaa, 0x0, 0x68, 0x86, 0xe3); +typedef struct IDirectPlaySP IDirectPlaySP, *LPDIRECTPLAYSP; + + +typedef BOOL (CALLBACK* LPENUMMRUCALLBACK)( LPCVOID lpData, + DWORD dwDataSize, + LPVOID lpContext ); + +/* For SP. Top 16 bits is dplay, bottom 16 is SP */ +#define DPSP_MAJORVERSION 0x00060000 +#define DPSP_DX5VERSION 0x00050000 +#define DPSP_DX3VERSION 0x00040000 + +#define DPSP_MAJORVERSIONMASK 0xFFFF0000 +#define DPSP_MINORVERSIONMASK 0x0000FFFF + + +/* Some flags */ +#define DPLAYI_PLAYER_SYSPLAYER 0x00000001 +#define DPLAYI_PLAYER_NAMESRVR 0x00000002 +#define DPLAYI_PLAYER_PLAYERINGROUP 0x00000004 +#define DPLAYI_PLAYER_PLAYERLOCAL 0x00000008 +#define DPLAYI_GROUP_SYSGROUP 0x00000020 +#define DPLAYI_GROUP_DPLAYOWNS 0x00000040 +#define DPLAYI_PLAYER_APPSERVER 0x00000080 +#define DPLAYI_GROUP_HIDDEN 0x00000400 + +/* Define the COM interface */ +#define ICOM_INTERFACE IDirectPlaySP +#define IDirectPlaySP_METHODS \ + ICOM_METHOD5(HRESULT,AddMRUEntry, LPCWSTR,lpSection, LPCWSTR,lpKey, LPCVOID,lpData, DWORD,dwDataSize, DWORD,dwMaxEntries ) \ + ICOM_METHOD6(HRESULT,CreateAddress, REFGUID,guidSP, REFGUID,guidDataType, LPCVOID,lpData, DWORD,dwDataSize, LPVOID,lpAddress,LPDWORD,lpdwAddressSize) \ + ICOM_METHOD4(HRESULT,EnumAddress, LPDPENUMADDRESSCALLBACK,lpEnumAddressCallback, LPCVOID,lpAddress, DWORD,dwAddressSize, LPVOID,lpContext ) \ + ICOM_METHOD4(HRESULT,EnumMRUEntries, LPCWSTR,lpSection, LPCWSTR,lpKey, LPENUMMRUCALLBACK,lpEnumMRUCallback, LPVOID,lpContext ) \ + ICOM_METHOD2(HRESULT,GetPlayerFlags, DPID,idPlayer, LPDWORD,lpdwPlayerFlags ) \ + ICOM_METHOD4(HRESULT,GetSPPlayerData, DPID,idPlayer, LPVOID*,lplpData, LPDWORD,lpdwDataSize, DWORD,dwFlags ) \ + ICOM_METHOD3(HRESULT,HandleMessage, LPVOID,lpMessageBody, DWORD,dwMessageBodySize, LPVOID,lpMessageHeader ) \ + ICOM_METHOD4(HRESULT,SetSPPlayerData, DPID,idPlayer, LPVOID,lpData, DWORD,dwDataSize, DWORD,dwFlags ) \ + ICOM_METHOD4(HRESULT,CreateCompoundAddress, LPCDPCOMPOUNDADDRESSELEMENT,lpElements, DWORD,dwElementCount, LPVOID,lpAddress, LPDWORD,lpdwAddressSize ) \ + ICOM_METHOD3(HRESULT,GetSPData, LPVOID*,lplpData, LPDWORD,dwDataSize, DWORD,dwFlags ) \ + ICOM_METHOD3(HRESULT,SetSPData, LPVOID,lpData, DWORD,dwDataSize, DWORD,dwFlags ) \ + ICOM_METHOD2(VOID,SendComplete, LPVOID,, DWORD, ) + +#define IDirectPlaySP_IMETHODS \ + IUnknown_IMETHODS \ + IDirectPlaySP_METHODS + +ICOM_DEFINE(IDirectPlaySP,IUnknown) +#undef ICOM_INTERFACE + +/*** IUnknown methods ***/ +#define IDirectPlaySP_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) +#define IDirectPlaySP_AddRef(p) ICOM_CALL (AddRef,p) +#define IDirectPlaySP_Release(p) ICOM_CALL (Release,p) +/*** IDirectPlaySP methods ***/ +#define IDirectPlaySP_AddMRUEntry ICOM_CALL5(AddMRUEntry,p,a,b,c,d,e) +#define IDirectPlaySP_CreateAddress ICOM_CALL6(CreateAddress,p,a,b,c,d,e,f) +#define IDirectPlaySP_EnumAddress ICOM_CALL4(EnumAddress,p,a,b,c,d) +#define IDirectPlaySP_EnumMRUEntries ICOM_CALL4(EnumMRUEntries,p,a,b,c,d) +#define IDirectPlaySP_GetPlayerFlags ICOM_CALL2(GetPlayerFlags,p,a,b) +#define IDirectPlaySP_GetSPPlayerData ICOM_CALL4(GetSPPlayerData,p,a,b,c,d) +#define IDirectPlaySP_HandleMessage ICOM_CALL3(HandleMessage,p,a,b,c) +#define IDirectPlaySP_SetSPPlayerData ICOM_CALL4(SetSPPlayerData,p,a,b,c,d) +#define IDirectPlaySP_CreateCompoundAddress ICOM_CALL4(CreateCompoundAddress,p,a,b,c,d) +#define IDirectPlaySP_GetSPData ICOM_CALL3(GetSPData,p,a,b,c) +#define IDirectPlaySP_SetSPData ICOM_CALL3(SetSPData,p,a,b,c) +#define IDirectPlaySP_SendComplete ICOM_CALL2(SendComplete,p,a,b) + +/* SP Callback stuff */ + +typedef struct tagDPSP_ADDPLAYERTOGROUPDATA +{ + DPID idPlayer; + DPID idGroup; + IDirectPlaySP* lpISP; +} DPSP_ADDPLAYERTOGROUPDATA, *LPDPSP_ADDPLAYERTOGROUPDATA; + +typedef struct tagDPSP_CLOSEDATA +{ + IDirectPlaySP* lpISP; +} DPSP_CLOSEDATA, *LPDPSP_CLOSEDATA; + +typedef struct tagDPSP_CREATEGROUPDATA +{ + DPID idGroup; + DWORD dwFlags; + LPVOID lpSPMessageHeader; + IDirectPlaySP* lpISP; +} DPSP_CREATEGROUPDATA, *LPDPSP_CREATEGROUPDATA; + +typedef struct tagDPSP_CREATEPLAYERDATA +{ + DPID idPlayer; + DWORD dwFlags; + LPVOID lpSPMessageHeader; + IDirectPlaySP* lpISP; +} DPSP_CREATEPLAYERDATA, *LPDPSP_CREATEPLAYERDATA; + +typedef struct tagDPSP_DELETEGROUPDATA +{ + DPID idGroup; + DWORD dwFlags; + IDirectPlaySP* lpISP; +} DPSP_DELETEGROUPDATA, *LPDPSP_DELETEGROUPDATA; + +typedef struct tagDPSP_DELETEPLAYERDATA +{ + DPID idPlayer; + DWORD dwFlags; + IDirectPlaySP* lpISP; +} DPSP_DELETEPLAYERDATA, *LPDPSP_DELETEPLAYERDATA; + +typedef struct tagDPSP_ENUMSESSIONSDATA +{ + LPVOID lpMessage; + DWORD dwMessageSize; + IDirectPlaySP* lpISP; + BOOL bReturnStatus; +} DPSP_ENUMSESSIONSDATA, *LPDPSP_ENUMSESSIONSDATA; + +typedef struct _DPSP_GETADDRESSDATA +{ + DPID idPlayer; + DWORD dwFlags; + LPDPADDRESS lpAddress; + LPDWORD lpdwAddressSize; + IDirectPlaySP* lpISP; +} DPSP_GETADDRESSDATA, *LPDPSP_GETADDRESSDATA; + +typedef struct tagDPSP_GETADDRESSCHOICESDATA +{ + LPDPADDRESS lpAddress; + LPDWORD lpdwAddressSize; + IDirectPlaySP* lpISP; +} DPSP_GETADDRESSCHOICESDATA, *LPDPSP_GETADDRESSCHOICESDATA; + +typedef struct tagDPSP_GETCAPSDATA +{ + DPID idPlayer; + LPDPCAPS lpCaps; + DWORD dwFlags; + IDirectPlaySP* lpISP; +} DPSP_GETCAPSDATA, *LPDPSP_GETCAPSDATA; + +typedef struct tagDPSP_OPENDATA +{ + BOOL bCreate; + LPVOID lpSPMessageHeader; + IDirectPlaySP* lpISP; + BOOL bReturnStatus; + DWORD dwOpenFlags; + DWORD dwSessionFlags; +} DPSP_OPENDATA, *LPDPSP_OPENDATA; + +typedef struct tagDPSP_REMOVEPLAYERFROMGROUPDATA +{ + DPID idPlayer; + DPID idGroup; + IDirectPlaySP* lpISP; +} DPSP_REMOVEPLAYERFROMGROUPDATA, *LPDPSP_REMOVEPLAYERFROMGROUPDATA; + +typedef struct tagDPSP_REPLYDATA +{ + LPVOID lpSPMessageHeader; + LPVOID lpMessage; + DWORD dwMessageSize; + DPID idNameServer; + IDirectPlaySP* lpISP; +} DPSP_REPLYDATA, *LPDPSP_REPLYDATA; + +typedef struct tagDPSP_SENDDATA +{ + DWORD dwFlags; + DPID idPlayerTo; + DPID idPlayerFrom; + LPVOID lpMessage; + DWORD dwMessageSize; + BOOL bSystemMessage; + IDirectPlaySP* lpISP; +} DPSP_SENDDATA, *LPDPSP_SENDDATA; + +typedef struct tagDPSP_SENDTOGROUPDATA +{ + DWORD dwFlags; + DPID idGroupTo; + DPID idPlayerFrom; + LPVOID lpMessage; + DWORD dwMessageSize; + IDirectPlaySP* lpISP; +} DPSP_SENDTOGROUPDATA, *LPDPSP_SENDTOGROUPDATA; + +typedef struct tagDPSP_SENDEXDATA +{ + IDirectPlaySP* lpISP; + DWORD dwFlags; + DPID idPlayerTo; + DPID idPlayerFrom; + LPSGBUFFER lpSendBuffers; + DWORD cBuffers; + DWORD dwMessageSize; + DWORD dwPriority; + DWORD dwTimeout; + LPVOID lpDPContext; + LPDWORD lpdwSPMsgID; + BOOL bSystemMessage; +} DPSP_SENDEXDATA, *LPDPSP_SENDEXDATA; + +typedef struct tagDPSP_SENDTOGROUPEXDATA +{ + IDirectPlaySP* lpISP; + DWORD dwFlags; + DPID idGroupTo; + DPID idPlayerFrom; + LPSGBUFFER lpSendBuffers; + DWORD cBuffers; + DWORD dwMessageSize; + DWORD dwPriority; + DWORD dwTimeout; + LPVOID lpDPContext; + LPDWORD lpdwSPMsgID; +} DPSP_SENDTOGROUPEXDATA, *LPDPSP_SENDTOGROUPEXDATA; + +typedef struct tagDPSP_GETMESSAGEQUEUEDATA +{ + IDirectPlaySP* lpISP; + DWORD dwFlags; + DPID idFrom; + DPID idTo; + LPDWORD lpdwNumMsgs; + LPDWORD lpdwNumBytes; +} DPSP_GETMESSAGEQUEUEDATA, *LPDPSP_GETMESSAGEQUEUEDATA; + +#define DPCANCELSEND_PRIORITY 0x00000001 +#define DPCANCELSEND_ALL 0x00000002 + +typedef struct tagDPSP_CANCELDATA +{ + IDirectPlaySP* lpISP; + DWORD dwFlags; + LPRGLPVOID lprglpvSPMsgID; + DWORD cSPMsgID; + DWORD dwMinPriority; + DWORD dwMaxPriority; +} DPSP_CANCELDATA, *LPDPSP_CANCELDATA; + +typedef struct tagDPSP_SHUTDOWNDATA +{ + IDirectPlaySP* lpISP; +} DPSP_SHUTDOWNDATA, *LPDPSP_SHUTDOWNDATA; + + +/* Prototypes returned by SPInit */ +typedef HRESULT (WINAPI *LPDPSP_CREATEPLAYER)(LPDPSP_CREATEPLAYERDATA); +typedef HRESULT (WINAPI *LPDPSP_DELETEPLAYER)(LPDPSP_DELETEPLAYERDATA); +typedef HRESULT (WINAPI *LPDPSP_SEND)(LPDPSP_SENDDATA); +typedef HRESULT (WINAPI *LPDPSP_ENUMSESSIONS)(LPDPSP_ENUMSESSIONSDATA); +typedef HRESULT (WINAPI *LPDPSP_REPLY)(LPDPSP_REPLYDATA); +typedef HRESULT (WINAPI *LPDPSP_SHUTDOWN)(void); +typedef HRESULT (WINAPI *LPDPSP_CREATEGROUP)(LPDPSP_CREATEGROUPDATA); +typedef HRESULT (WINAPI *LPDPSP_DELETEGROUP)(LPDPSP_DELETEGROUPDATA); +typedef HRESULT (WINAPI *LPDPSP_ADDPLAYERTOGROUP)(LPDPSP_ADDPLAYERTOGROUPDATA); +typedef HRESULT (WINAPI *LPDPSP_REMOVEPLAYERFROMGROUP)(LPDPSP_REMOVEPLAYERFROMGROUPDATA); +typedef HRESULT (WINAPI *LPDPSP_GETCAPS)(LPDPSP_GETCAPSDATA); +typedef HRESULT (WINAPI *LPDPSP_GETADDRESS)(LPDPSP_GETADDRESSDATA); +typedef HRESULT (WINAPI *LPDPSP_GETADDRESSCHOICES)(LPDPSP_GETADDRESSCHOICESDATA); +typedef HRESULT (WINAPI *LPDPSP_OPEN)(LPDPSP_OPENDATA); +typedef HRESULT (WINAPI *LPDPSP_CLOSE)(void); +typedef HRESULT (WINAPI *LPDPSP_SENDTOGROUP)(LPDPSP_SENDTOGROUPDATA); +typedef HRESULT (WINAPI *LPDPSP_SHUTDOWNEX)(LPDPSP_SHUTDOWNDATA); +typedef HRESULT (WINAPI *LPDPSP_CLOSEEX)(LPDPSP_CLOSEDATA); +typedef HRESULT (WINAPI *LPDPSP_SENDEX)(LPDPSP_SENDEXDATA); +typedef HRESULT (WINAPI *LPDPSP_SENDTOGROUPEX)(LPDPSP_SENDTOGROUPEXDATA); +typedef HRESULT (WINAPI *LPDPSP_CANCEL)(LPDPSP_CANCELDATA); +typedef HRESULT (WINAPI *LPDPSP_GETMESSAGEQUEUE)(LPDPSP_GETMESSAGEQUEUEDATA); + + +typedef struct tagDPSP_SPCALLBACKS +{ + DWORD dwSize; + DWORD dwVersion; + + LPDPSP_ENUMSESSIONS EnumSessions; /* Must be provided */ + LPDPSP_REPLY Reply; /* Must be provided */ + LPDPSP_SEND Send; /* Must be provided */ + LPDPSP_ADDPLAYERTOGROUP AddPlayerToGroup; /* Optional */ + LPDPSP_CLOSE Close; /* Optional */ + LPDPSP_CREATEGROUP CreateGroup; /* Optional */ + LPDPSP_CREATEPLAYER CreatePlayer; /* Optional */ + LPDPSP_DELETEGROUP DeleteGroup; /* Optional */ + LPDPSP_DELETEPLAYER DeletePlayer; /* Optional */ + LPDPSP_GETADDRESS GetAddress; /* Optional */ + LPDPSP_GETCAPS GetCaps; /* Optional */ + LPDPSP_OPEN Open; /* Optional */ + LPDPSP_REMOVEPLAYERFROMGROUP RemovePlayerFromGroup; /* Optional */ + LPDPSP_SENDTOGROUP SendToGroup; /* Optional */ + LPDPSP_SHUTDOWN Shutdown; /* Optional */ + + LPDPSP_CLOSEEX CloseEx; /* Optional */ + LPDPSP_SHUTDOWNEX ShutdownEx; /* Optional */ + LPDPSP_GETADDRESSCHOICES GetAddressChoices; /* Optional */ + + LPDPSP_SENDEX SendEx; /* Optional */ + LPDPSP_SENDTOGROUPEX SendToGroupEx; /* Optional */ + LPDPSP_CANCEL Cancel; /* Optional */ + LPDPSP_GETMESSAGEQUEUE GetMessageQueue; /* Optional */ +} DPSP_SPCALLBACKS, *LPDPSP_SPCALLBACKS; + +typedef struct tagSPINITDATA +{ + LPDPSP_SPCALLBACKS lpCB; + IDirectPlaySP* lpISP; + LPWSTR lpszName; + LPGUID lpGuid; + DWORD dwReserved1; + DWORD dwReserved2; + DWORD dwSPHeaderSize; + LPDPADDRESS lpAddress; + DWORD dwAddressSize; + DWORD dwSPVersion; +} SPINITDATA, *LPSPINITDATA; + +typedef HRESULT (WINAPI *LPDPSP_SPINIT)(LPSPINITDATA); + +/* This variable is exported from the DLL at ordinal 6 to be accessed by the + * SP directly + */ +extern DWORD gdwDPlaySPRefCount; + +#endif + diff --git a/dlls/dplayx/dplayx_global.c b/dlls/dplayx/dplayx_global.c index 1e171a68d18..59d422590ca 100644 --- a/dlls/dplayx/dplayx_global.c +++ b/dlls/dplayx/dplayx_global.c @@ -10,11 +10,14 @@ * dplayx.dll data which is accessible from all processes. */ -#include #include "debugtools.h" #include "winbase.h" #include "winerror.h" #include "wine/unicode.h" +#include "heap.h" + +#include "wingdi.h" +#include "winuser.h" #include "dplayx_global.h" #include "dplayx_messages.h" /* For CreateMessageReceptionThread only */ @@ -42,9 +45,9 @@ static LPVOID lpSharedStaticData = NULL; /* HACK for simple global data right now */ -#define dwStaticSharedSize (128 * 1024) /* FIXME: Way too much */ -#define dwDynamicSharedSize (128 * 1024) /* FIXME: Enough? */ -#define dwTotalSharedSize (dwStaticSharedSize + dwDynamicSharedSize) +#define dwStaticSharedSize (128 * 1024) /* 128 KBytes */ +#define dwDynamicSharedSize (512 * 1024) /* 512 KBytes */ +#define dwTotalSharedSize ( dwStaticSharedSize + dwDynamicSharedSize ) /* FIXME: Is there no easier way? */ @@ -53,7 +56,6 @@ static LPVOID lpSharedStaticData = NULL; * Each block has 4 bytes which are 0 unless used */ #define dwBlockSize 512 #define dwMaxBlock (dwDynamicSharedSize/dwBlockSize) -DWORD dwBlockOn = 0; typedef struct { @@ -61,7 +63,7 @@ typedef struct DWORD data[dwBlockSize-sizeof(DWORD)]; } DPLAYX_MEM_SLICE; -DPLAYX_MEM_SLICE* lpMemArea; +static DPLAYX_MEM_SLICE* lpMemArea; void DPLAYX_PrivHeapFree( LPVOID addr ); void DPLAYX_PrivHeapFree( LPVOID addr ) @@ -81,6 +83,7 @@ void DPLAYX_PrivHeapFree( LPVOID addr ) lpMemArea[ dwBlockUsed ].used = 0; } +/* FIXME: This should be static, but is being used for a hack right now */ LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size ); LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size ) { @@ -149,17 +152,19 @@ typedef struct tagDPLAYX_LOBBYDATA /* Information for dplobby interfaces */ DWORD dwAppID; - HANDLE hReceiveEvent; DWORD dwAppLaunchedFromID; /* Should this lobby app send messages to creator at important life * stages */ - BOOL bInformOnConnect; /* FIXME: Not used yet */ - BOOL bInformOnSettingRead; - BOOL bInformOnAppDeath; /* FIXME: Not used yet */ + HANDLE hInformOnAppStart; + HANDLE hInformOnAppDeath; + HANDLE hInformOnSettingRead; + /* Sundries */ BOOL bWaitForConnectionSettings; + DWORD dwLobbyMsgThreadId; + } DPLAYX_LOBBYDATA, *LPDPLAYX_LOBBYDATA; @@ -190,6 +195,7 @@ BOOL DPLAYX_ConstructData(void) SECURITY_ATTRIBUTES s_attrib; BOOL bInitializeSharedMemory = FALSE; LPVOID lpDesiredMemoryMapStart = (LPVOID)0x50000000; + HANDLE hInformOnStart; TRACE( "DPLAYX dll loaded - construct called\n" ); @@ -309,6 +315,22 @@ BOOL DPLAYX_ConstructData(void) DPLAYX_ReleaseSemaphore(); + /* Everything was created correctly. Signal the lobby client that + * we started up correctly + */ + if( DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, FALSE ) && + hInformOnStart + ) + { + BOOL bSuccess; + bSuccess = SetEvent( hInformOnStart ); + TRACE( "Signalling lobby app start event %u %s\n", + hInformOnStart, bSuccess ? "succeed" : "failed" ); + + /* Close out handle */ + DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, TRUE ); + } + return TRUE; } @@ -318,8 +340,26 @@ BOOL DPLAYX_ConstructData(void) ***************************************************************************/ BOOL DPLAYX_DestructData(void) { + HANDLE hInformOnDeath; + TRACE( "DPLAYX dll unloaded - destruct called\n" ); + /* If required, inform that this app is dying */ + if( DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, FALSE ) && + hInformOnDeath + ) + { + BOOL bSuccess; + bSuccess = SetEvent( hInformOnDeath ); + TRACE( "Signalling lobby app death event %u %s\n", + hInformOnDeath, bSuccess ? "succeed" : "failed" ); + + /* Close out handle */ + DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, TRUE ); + } + + /* DO CLEAN UP (LAST) */ + /* Delete the semaphore */ CloseHandle( hDplayxSema ); @@ -334,9 +374,6 @@ BOOL DPLAYX_DestructData(void) void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData ) { ZeroMemory( lpData, sizeof( *lpData ) ); - - /* Set the handle to a better invalid value */ - lpData->hReceiveEvent = INVALID_HANDLE_VALUE; } /* NOTE: This must be called with the semaphore aquired. @@ -370,7 +407,7 @@ BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppID, LPDPLAYX_LOBBYDATA* lplpDplData ) } /* Reserve a spot for the new appliction. TRUE means success and FALSE failure. */ -BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent ) +BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID ) { UINT i; @@ -388,16 +425,16 @@ BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent ) if( lobbyData[ i ].dwAppID == 0 ) { /* This process is now lobbied */ - TRACE( "Setting lobbyData[%u] for (0x%08lx,%u,0x%08lx)\n", - i, dwAppID, hReceiveEvent, GetCurrentProcessId() ); + TRACE( "Setting lobbyData[%u] for (0x%08lx,0x%08lx)\n", + i, dwAppID, GetCurrentProcessId() ); lobbyData[ i ].dwAppID = dwAppID; - lobbyData[ i ].hReceiveEvent = hReceiveEvent; lobbyData[ i ].dwAppLaunchedFromID = GetCurrentProcessId(); - lobbyData[ i ].bInformOnConnect = TRUE; - lobbyData[ i ].bInformOnSettingRead = TRUE; - lobbyData[ i ].bInformOnAppDeath = TRUE; + /* FIXME: Where is the best place for this? In interface or here? */ + lobbyData[ i ].hInformOnAppStart = 0; + lobbyData[ i ].hInformOnAppDeath = 0; + lobbyData[ i ].hInformOnSettingRead = 0; DPLAYX_ReleaseSemaphore(); return TRUE; @@ -437,14 +474,114 @@ BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID ) return FALSE; } +BOOL DPLAYX_SetLobbyHandles( DWORD dwAppID, + HANDLE hStart, HANDLE hDeath, HANDLE hConnRead ) +{ + LPDPLAYX_LOBBYDATA lpLData; + + /* Need to explictly give lobby application. Can't set for yourself */ + if( dwAppID == 0 ) + { + return FALSE; + } + + DPLAYX_AquireSemaphore(); + + if( !DPLAYX_IsAppIdLobbied( dwAppID, &lpLData ) ) + { + DPLAYX_ReleaseSemaphore(); + return FALSE; + } + + lpLData->hInformOnAppStart = hStart; + lpLData->hInformOnAppDeath = hDeath; + lpLData->hInformOnSettingRead = hConnRead; + + DPLAYX_ReleaseSemaphore(); + + return TRUE; +} + +BOOL DPLAYX_GetThisLobbyHandles( LPHANDLE lphStart, + LPHANDLE lphDeath, + LPHANDLE lphConnRead, + BOOL bClearSetHandles ) +{ + LPDPLAYX_LOBBYDATA lpLData; + + DPLAYX_AquireSemaphore(); + + if( !DPLAYX_IsAppIdLobbied( 0, &lpLData ) ) + { + DPLAYX_ReleaseSemaphore(); + return FALSE; + } + + if( lphStart != NULL ) + { + if( lpLData->hInformOnAppStart == 0 ) + { + DPLAYX_ReleaseSemaphore(); + return FALSE; + } + + *lphStart = lpLData->hInformOnAppStart; + + if( bClearSetHandles ) + { + CloseHandle( lpLData->hInformOnAppStart ); + lpLData->hInformOnAppStart = 0; + } + } + + if( lphDeath != NULL ) + { + if( lpLData->hInformOnAppDeath == 0 ) + { + DPLAYX_ReleaseSemaphore(); + return FALSE; + } + + *lphDeath = lpLData->hInformOnAppDeath; + + if( bClearSetHandles ) + { + CloseHandle( lpLData->hInformOnAppDeath ); + lpLData->hInformOnAppDeath = 0; + } + } + + if( lphConnRead != NULL ) + { + if( lpLData->hInformOnSettingRead == 0 ) + { + DPLAYX_ReleaseSemaphore(); + return FALSE; + } + + *lphConnRead = lpLData->hInformOnSettingRead; + + if( bClearSetHandles ) + { + CloseHandle( lpLData->hInformOnSettingRead ); + lpLData->hInformOnSettingRead = 0; + } + } + + DPLAYX_ReleaseSemaphore(); + + return TRUE; +} + + HRESULT DPLAYX_GetConnectionSettingsA ( DWORD dwAppID, LPVOID lpData, - LPDWORD lpdwDataSize, - LPBOOL lpbSendHaveReadMessage ) + LPDWORD lpdwDataSize ) { LPDPLAYX_LOBBYDATA lpDplData; DWORD dwRequiredDataSize = 0; + HANDLE hInformOnSettingRead; DPLAYX_AquireSemaphore(); @@ -472,23 +609,33 @@ HRESULT DPLAYX_GetConnectionSettingsA return DPERR_BUFFERTOOSMALL; } - /* They have gotten the information */ - *lpbSendHaveReadMessage = lpDplData->bInformOnSettingRead; - lpDplData->bInformOnSettingRead = FALSE; - DPLAYX_CopyConnStructA( (LPDPLCONNECTION)lpData, lpDplData->lpConn ); DPLAYX_ReleaseSemaphore(); + /* They have gotten the information - signal the event if required */ + if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) && + hInformOnSettingRead + ) + { + BOOL bSuccess; + bSuccess = SetEvent( hInformOnSettingRead ); + TRACE( "Signalling setting read event %u %s\n", + hInformOnSettingRead, bSuccess ? "succeed" : "failed" ); + + /* Close out handle */ + DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE ); + } + return DP_OK; } /* Assumption: Enough contiguous space was allocated at dest */ void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src ) { - BYTE* lpStartOfFreeSpace; + BYTE* lpStartOfFreeSpace; - memcpy( dest, src, sizeof( DPLCONNECTION ) ); + CopyMemory( dest, src, sizeof( DPLCONNECTION ) ); lpStartOfFreeSpace = ((BYTE*)dest) + sizeof( DPLCONNECTION ); @@ -497,7 +644,7 @@ void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src ) { dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace; lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 ); - memcpy( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) ); + CopyMemory( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) ); /* Session names may or may not exist */ if( src->lpSessionDesc->sess.lpszSessionNameA ) @@ -505,7 +652,7 @@ void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src ) strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->sess.lpszSessionNameA ); dest->lpSessionDesc->sess.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace; lpStartOfFreeSpace += - strlen( (LPSTR)dest->lpSessionDesc->sess.lpszSessionName ) + 1; + strlen( (LPSTR)dest->lpSessionDesc->sess.lpszSessionNameA ) + 1; } if( src->lpSessionDesc->pass.lpszPasswordA ) @@ -522,7 +669,7 @@ void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src ) { dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace; lpStartOfFreeSpace += sizeof( DPNAME ); - memcpy( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) ); + CopyMemory( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) ); if( src->lpPlayerName->psn.lpszShortNameA ) { @@ -546,7 +693,7 @@ void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src ) if( src->lpAddress ) { dest->lpAddress = (LPVOID)lpStartOfFreeSpace; - memcpy( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize ); + CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize ); /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */ } } @@ -554,11 +701,11 @@ void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src ) HRESULT DPLAYX_GetConnectionSettingsW ( DWORD dwAppID, LPVOID lpData, - LPDWORD lpdwDataSize, - LPBOOL lpbSendHaveReadMessage ) + LPDWORD lpdwDataSize ) { LPDPLAYX_LOBBYDATA lpDplData; DWORD dwRequiredDataSize = 0; + HANDLE hInformOnSettingRead; DPLAYX_AquireSemaphore(); @@ -584,14 +731,24 @@ HRESULT DPLAYX_GetConnectionSettingsW return DPERR_BUFFERTOOSMALL; } - /* They have gotten the information */ - *lpbSendHaveReadMessage = lpDplData->bInformOnSettingRead; - lpDplData->bInformOnSettingRead = FALSE; - DPLAYX_CopyConnStructW( (LPDPLCONNECTION)lpData, lpDplData->lpConn ); DPLAYX_ReleaseSemaphore(); + /* They have gotten the information - signal the event if required */ + if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) && + hInformOnSettingRead + ) + { + BOOL bSuccess; + bSuccess = SetEvent( hInformOnSettingRead ); + TRACE( "Signalling setting read event %u %s\n", + hInformOnSettingRead, bSuccess ? "succeed" : "failed" ); + + /* Close out handle */ + DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE ); + } + return DP_OK; } @@ -600,7 +757,7 @@ void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src ) { BYTE* lpStartOfFreeSpace; - memcpy( dest, src, sizeof( DPLCONNECTION ) ); + CopyMemory( dest, src, sizeof( DPLCONNECTION ) ); lpStartOfFreeSpace = ( (BYTE*)dest) + sizeof( DPLCONNECTION ); @@ -609,7 +766,7 @@ void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src ) { dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace; lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 ); - memcpy( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) ); + CopyMemory( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) ); /* Session names may or may not exist */ if( src->lpSessionDesc->sess.lpszSessionName ) @@ -634,7 +791,7 @@ void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src ) { dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace; lpStartOfFreeSpace += sizeof( DPNAME ); - memcpy( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) ); + CopyMemory( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) ); if( src->lpPlayerName->psn.lpszShortName ) { @@ -658,7 +815,7 @@ void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src ) if( src->lpAddress ) { dest->lpAddress = (LPVOID)lpStartOfFreeSpace; - memcpy( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize ); + CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize ); /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */ } @@ -883,7 +1040,8 @@ DWORD DPLAYX_SizeOfLobbyDataW( LPDPLCONNECTION lpConn ) LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateSessionDesc2A( LPCDPSESSIONDESC2 lpSessionSrc ) { LPDPSESSIONDESC2 lpSessionDest = - (LPDPSESSIONDESC2)DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, sizeof( *lpSessionSrc ) ); + (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof( *lpSessionSrc ) ); DPLAYX_CopyIntoSessionDesc2A( lpSessionDest, lpSessionSrc ); return lpSessionDest; @@ -893,17 +1051,19 @@ LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateSessionDesc2A( LPCDPSESSIONDESC2 lpSessio BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2 lpSessionDest, LPCDPSESSIONDESC2 lpSessionSrc ) { - memcpy( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) ); + CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) ); if( lpSessionSrc->sess.lpszSessionNameA ) { lpSessionDest->sess.lpszSessionNameA = - DPLAYX_strdupA( HEAP_ZERO_MEMORY, lpSessionSrc->sess.lpszSessionNameA ); + HEAP_strdupA( GetProcessHeap(), + HEAP_ZERO_MEMORY, lpSessionSrc->sess.lpszSessionNameA ); } if( lpSessionSrc->pass.lpszPasswordA ) { lpSessionDest->pass.lpszPasswordA = - DPLAYX_strdupA( HEAP_ZERO_MEMORY, lpSessionSrc->pass.lpszPasswordA ); + HEAP_strdupA( GetProcessHeap(), + HEAP_ZERO_MEMORY, lpSessionSrc->pass.lpszPasswordA ); } return TRUE; @@ -1002,6 +1162,24 @@ BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void) return bFound; } +BOOL DPLAYX_SetLobbyMsgThreadId( DWORD dwAppId, DWORD dwThreadId ) +{ + LPDPLAYX_LOBBYDATA lpLobbyData; + + DPLAYX_AquireSemaphore(); + + if( !DPLAYX_IsAppIdLobbied( dwAppId, &lpLobbyData ) ) + { + DPLAYX_ReleaseSemaphore(); + return FALSE; + } + + lpLobbyData->dwLobbyMsgThreadId = dwThreadId; + + DPLAYX_ReleaseSemaphore(); + + return TRUE; +} /* NOTE: This is potentially not thread safe. You are not guaranteed to end up with the correct string printed in the case where the HRESULT is not @@ -1149,7 +1327,7 @@ LPCSTR DPLAYX_HresultToString(HRESULT hr) /* For errors not in the list, return HRESULT as a string This part is not thread safe */ WARN( "Unknown error 0x%08lx\n", hr ); - sprintf( szTempStr, "0x%08lx", hr ); + wsprintfA( szTempStr, "0x%08lx", hr ); return szTempStr; } } diff --git a/dlls/dplayx/dplayx_global.h b/dlls/dplayx/dplayx_global.h index 569edb1392f..bc51533ee11 100644 --- a/dlls/dplayx/dplayx_global.h +++ b/dlls/dplayx/dplayx_global.h @@ -9,12 +9,10 @@ BOOL DPLAYX_DestructData(void); HRESULT DPLAYX_GetConnectionSettingsA ( DWORD dwAppID, LPVOID lpData, - LPDWORD lpdwDataSize, - LPBOOL lpbSendHaveReadMessage ); + LPDWORD lpdwDataSize ); HRESULT DPLAYX_GetConnectionSettingsW ( DWORD dwAppID, LPVOID lpData, - LPDWORD lpdwDataSize, - LPBOOL lpbSendHaveReadMessage ); + LPDWORD lpdwDataSize ); HRESULT DPLAYX_SetConnectionSettingsA ( DWORD dwFlags, DWORD dwAppID, @@ -23,16 +21,33 @@ HRESULT DPLAYX_SetConnectionSettingsW ( DWORD dwFlags, DWORD dwAppID, LPDPLCONNECTION lpConn ); -BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent ); +BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID ); BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID ); BOOL DPLAYX_WaitForConnectionSettings( BOOL bWait ); BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void); +BOOL DPLAYX_SetLobbyHandles( DWORD dwAppID, + HANDLE hStart, HANDLE hDeath, HANDLE hConnRead ); +BOOL DPLAYX_GetThisLobbyHandles( LPHANDLE lphStart, + LPHANDLE lphDeath, + LPHANDLE lphConnRead, BOOL bClearSetHandles ); + LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateLocalSession( UINT* index ); BOOL DPLAYX_CopyLocalSession( UINT* index, LPDPSESSIONDESC2 lpsd ); void DPLAYX_SetLocalSession( LPCDPSESSIONDESC2 lpsd ); +BOOL DPLAYX_SetLobbyMsgThreadId( DWORD dwAppId, DWORD dwThreadId ); + +/* FIXME: This should not be here */ +LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size ); +void DPLAYX_PrivHeapFree( LPVOID addr ); + +LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str ); +LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str ); +/* FIXME: End shared data alloc which should be local */ + + /* Convert a DP or DPL HRESULT code into a string for human consumption */ LPCSTR DPLAYX_HresultToString( HRESULT hr ); diff --git a/dlls/dplayx/dplayx_main.c b/dlls/dplayx/dplayx_main.c index 56702f9c818..77c0da7185b 100644 --- a/dlls/dplayx/dplayx_main.c +++ b/dlls/dplayx/dplayx_main.c @@ -5,19 +5,24 @@ * * contact */ - +#include "winerror.h" #include "winbase.h" #include "debugtools.h" -#include "initguid.h" -#include "dplay.h" -#include "dplobby.h" +#include "initguid.h" /* To define the GUIDs */ +#include "dplaysp.h" #include "dplayx_global.h" DEFAULT_DEBUG_CHANNEL(dplay); +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + static DWORD DPLAYX_dwProcessesAttached = 0; +/* This is a globally exported variable at ordinal 6 of DPLAYX.DLL */ +DWORD gdwDPlaySPRefCount = 0; /* FIXME: Should it be initialized here? */ + + BOOL WINAPI DPLAYX_LibMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) { @@ -59,3 +64,20 @@ BOOL WINAPI DPLAYX_LibMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReser return TRUE; } + +/*********************************************************************** + * DllCanUnloadNow (DPLAYX.10) + */ +HRESULT WINAPI DPLAYX_DllCanUnloadNow(void) +{ + HRESULT hr = ( gdwDPlaySPRefCount > 0 ) ? S_FALSE : S_OK; + + /* FIXME: Should I be putting a check in for class factory objects + * as well + */ + + TRACE( ": returning 0x%08lx\n", hr ); + + return hr; +} + diff --git a/dlls/dplayx/dplayx_messages.c b/dlls/dplayx/dplayx_messages.c index 5fb41e6f235..bc23ef2d50e 100644 --- a/dlls/dplayx/dplayx_messages.c +++ b/dlls/dplayx/dplayx_messages.c @@ -9,48 +9,130 @@ #include "winbase.h" #include "debugtools.h" +#include "wingdi.h" +#include "winuser.h" + #include "dplayx_messages.h" DEFAULT_DEBUG_CHANNEL(dplay) +typedef struct tagMSGTHREADINFO +{ + HANDLE hStart; + HANDLE hDeath; + HANDLE hSettingRead; + HANDLE hNotifyEvent; +} MSGTHREADINFO, *LPMSGTHREADINFO; -static DWORD CALLBACK DPLAYX_MSG_ThreadMain( LPVOID lpContext ); + +static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext ); /* Create the message reception thread to allow the application to receive * asynchronous message reception */ -DWORD CreateMessageReceptionThread( HANDLE hNotifyEvent ) +DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart, + HANDLE hDeath, HANDLE hConnRead ) { - DWORD dwMsgThreadId; + DWORD dwMsgThreadId; + LPMSGTHREADINFO lpThreadInfo; - if( !DuplicateHandle( 0, hNotifyEvent, 0, NULL, 0, FALSE, 0 ) ) + lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) ); + if( lpThreadInfo == NULL ) { - ERR( "Unable to duplicate event handle\n" ); return 0; } - /* FIXME: Should most likely store that thread handle */ - CreateThread( NULL, /* Security attribs */ - 0, /* Stack */ - DPLAYX_MSG_ThreadMain, /* Msg reception function */ - (LPVOID)hNotifyEvent, /* Msg reception function parameter */ - 0, /* Flags */ - &dwMsgThreadId /* Updated with thread id */ - ); + /* The notify event may or may not exist. Depends if async comm or not */ + if( hNotifyEvent && + !DuplicateHandle( GetCurrentProcess(), hNotifyEvent, + GetCurrentProcess(), &lpThreadInfo->hNotifyEvent, + 0, FALSE, DUPLICATE_SAME_ACCESS ) ) + { + ERR( "Unable to duplicate event handle\n" ); + goto error; + } + + /* These 3 handles don't need to be duplicated because we don't keep a + * reference to them where they're created. They're created specifically + * for the message thread + */ + lpThreadInfo->hStart = hStart; + lpThreadInfo->hDeath = hDeath; + lpThreadInfo->hSettingRead = hConnRead; + + if( !CreateThread( NULL, /* Security attribs */ + 0, /* Stack */ + DPL_MSG_ThreadMain, /* Msg reception function */ + lpThreadInfo, /* Msg reception func parameter */ + 0, /* Flags */ + &dwMsgThreadId /* Updated with thread id */ + ) + ) + { + ERR( "Unable to create msg thread\n" ); + goto error; + } + + /* FIXME: Should I be closing the handle to the thread or does that + terminate the thread? */ return dwMsgThreadId; + +error: + + HeapFree( GetProcessHeap(), 0, lpThreadInfo ); + + return 0; } -static DWORD CALLBACK DPLAYX_MSG_ThreadMain( LPVOID lpContext ) + +static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext ) { - HANDLE hMsgEvent = (HANDLE)lpContext; + LPMSGTHREADINFO lpThreadInfo = (LPMSGTHREADINFO)lpContext; + DWORD dwWaitResult; + + TRACE( "Msg thread created. Waiting on app startup\n" ); + + /* Wait to ensure that the lobby application is started w/ 1 min timeout */ + dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ ); + if( dwWaitResult == WAIT_TIMEOUT ) + { + FIXME( "Should signal app/wait creation failure (0x%08lx)\n", dwWaitResult ); + goto end_of_thread; + } + + /* Close this handle as it's not needed anymore */ + CloseHandle( lpThreadInfo->hStart ); + lpThreadInfo->hStart = 0; + + /* Wait until the lobby knows what it is */ + dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE ); + if( dwWaitResult == WAIT_TIMEOUT ) + { + ERR( "App Read connection setting timeout fail (0x%08lx)\n", dwWaitResult ); + } + + /* Close this handle as it's not needed anymore */ + CloseHandle( lpThreadInfo->hSettingRead ); + lpThreadInfo->hSettingRead = 0; + + TRACE( "App created && intialized starting main message reception loop\n" ); for ( ;; ) { - FIXME( "Ho Hum. Msg thread with nothing to do on handle %u\n", hMsgEvent ); + MSG lobbyMsg; +#ifdef STRICT + HANDLE hNullHandle = NULL; +#else + HANDLE hNullHandle = 0; +#endif - SleepEx( 10000, FALSE ); /* 10 secs */ + GetMessageW( &lobbyMsg, hNullHandle, 0, 0 ); } - CloseHandle( hMsgEvent ); +end_of_thread: + TRACE( "Msg thread exiting!\n" ); + HeapFree( GetProcessHeap(), 0, lpThreadInfo ); + + return 0; } diff --git a/dlls/dplayx/dplayx_messages.h b/dlls/dplayx/dplayx_messages.h index 117678ff555..7c8cd07a0a0 100644 --- a/dlls/dplayx/dplayx_messages.h +++ b/dlls/dplayx/dplayx_messages.h @@ -1,10 +1,136 @@ -#ifndef __WINE_DPLAYX_MESSAGES -#define __WINE_DPLAYX_MESSAGES +#ifndef __WINE_DPLAYX_MESSAGES__ +#define __WINE_DPLAYX_MESSAGES__ #include "windef.h" +#include "dplay.h" +#include "rpc.h" /* For GUID */ -DWORD CreateMessageReceptionThread( HANDLE hNotifyEvent ); +DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart, + HANDLE hDeath, HANDLE hConnRead ); +/* Message types etc. */ +#include "pshpack1.h" + +/* Non provided messages for DPLAY - guess work which may be wrong :( */ +#define DPMSGCMD_ENUMSESSIONSREPLY 1 +#define DPMSGCMD_ENUMSESSIONSREQUEST 2 + +#define DPMSGCMD_GETSETNAMETABLE 3 /* Request info from NS about + existing players/groups etc. Is + also used for reply */ + +#define DPMSGCMD_REQUESTNEWPLAYERID 5 + +#define DPMSGCMD_NEWPLAYERIDREPLY 7 +#define DPMSGCMD_CREATESESSION 8 +#define DPMSGCMD_CREATENEWPLAYER 9 +#define DPMSGCMD_SYSTEMMESSAGE 10 + +#define DPMSGCMD_DELETEGROUP 12 + +#define DPMSGCMD_ENUMGROUPS 17 + +/* This is what DP 6 defines it as. Don't know what it means. All messages + * defined below are DPMSGVER_DP6. + */ +#define DPMSGVER_DP6 11 + +/* MAGIC number at the start of all dplay packets ("play" in ASCII) */ +#define DPMSGMAGIC_DPLAYMSG 0x79616c70 + +/* All messages sent from the system are sent with this at the beginning of + * the message. + */ + +/* Size is 4 bytes */ +typedef struct tagDPMSG_SENDENVELOPE +{ + DWORD dwMagic; + WORD wCommandId; + WORD wVersion; +} DPMSG_SENDENVELOPE, *LPDPMSG_SENDENVELOPE; +typedef const DPMSG_SENDENVELOPE* LPCDPMSG_SENDENVELOPE; + +typedef struct tagDPMSG_SYSMSGENVELOPE +{ + DWORD dwPlayerFrom; + DWORD dwPlayerTo; +} DPMSG_SYSMSGENVELOPE, *LPDPMSG_SYSMSGENVELOPE; +typedef const DPMSG_SYSMSGENVELOPE* LPCDPMSG_SYSMSGENVELOPE; + + +typedef struct tagDPMSG_ENUMSESSIONSREPLY +{ + DPMSG_SENDENVELOPE envelope; + +#if 0 + DWORD dwSize; /* Size of DPSESSIONDESC2 struct */ + DWORD dwFlags; /* Sessions flags */ + + GUID guidInstance; /* Not 100% sure this is what it is... */ + + GUID guidApplication; + + DWORD dwMaxPlayers; + DWORD dwCurrentPlayers; + + BYTE unknown[36]; +#else + DPSESSIONDESC2 sd; +#endif + + DWORD dwUnknown; /* Seems to be equal to 0x5c which is a "\\" */ + /* Encryption package string? */ + + /* At the end we have ... */ + /* WCHAR wszSessionName[1]; Var length with NULL terminal */ + +} DPMSG_ENUMSESSIONSREPLY, *LPDPMSG_ENUMSESSIONSREPLY; +typedef const DPMSG_ENUMSESSIONSREPLY* LPCDPMSG_ENUMSESSIONSREPLY; + +typedef struct tagDPMSG_ENUMSESSIONSREQUEST +{ + DPMSG_SENDENVELOPE envelope; + + GUID guidApplication; + + DWORD dwPasswordSize; /* A Guess. This is normally 0x00000000. */ + /* This might be the name server DPID which + is needed for the reply */ + + DWORD dwFlags; /* dwFlags from EnumSessions */ + +} DPMSG_ENUMSESSIONSREQUEST, *LPDPMSG_ENUMSESSIONSREQUEST; +typedef const DPMSG_ENUMSESSIONSREQUEST* LPCDPMSG_ENUMSESSIONSREQUEST; + +/* Size is 146 received - with 18 or 20 bytes header = ~128 bytes */ +typedef struct tagDPMSG_CREATESESSION +{ + DPMSG_SENDENVELOPE envelope; +} DPMSG_CREATESESSION, *LPDPMSG_CREATESESSION; +typedef const DPMSG_CREATESESSION* LPCDPMSG_CREATESESSION; + +/* 28 bytes - ~18 header ~= 10 bytes msg */ +typedef struct tagDPMSG_REQUESTNEWPLAYERID +{ + DPMSG_SENDENVELOPE envelope; + + + +} DPMSG_REQUESTNEWPLAYERID, *LPDPMSG_REQUESTNEWPLAYERID; +typedef const DPMSG_REQUESTNEWPLAYERID* LPCDPMSG_REQUESTNEWPLAYERID; + +/* 64 byte - ~18 header ~= 46 bytes msg */ +typedef struct tagDPMSG_NEWPLAYERIDREPLY +{ + DPMSG_SENDENVELOPE envelope; + +} DPMSG_NEWPLAYERIDREPLY, *LPDPMSG_NEWPLAYERIDREPLY; +typedef const DPMSG_NEWPLAYERIDREPLY* LPCDPMSG_NEWPLAYERIDREPLY; + + +#include "poppack.h" + #endif diff --git a/dlls/dplayx/dplayx_queue.h b/dlls/dplayx/dplayx_queue.h index 471f25c0e74..142713a6801 100644 --- a/dlls/dplayx/dplayx_queue.h +++ b/dlls/dplayx/dplayx_queue.h @@ -7,6 +7,8 @@ #ifndef __WINE_DPLAYX_QUEUE_H #define __WINE_DPLAYX_QUEUE_H +#include "winbase.h" + #define DPQ_INSERT(a,b,c) DPQ_INSERT_IN_TAIL(a,b,c) /* @@ -33,6 +35,19 @@ do{ \ (head).lpQHLast = &(head).lpQHFirst; \ } while(0) +/* Front of the queue */ +#define DPQ_FIRST( head ) ( (head).lpQHFirst ) + +/* Check if the queue has any elements */ +#define DPQ_IS_EMPTY( head ) ( DPQ_FIRST(head) == NULL ) + +/* Next entry -- FIXME: Convert everything over to this macro ... */ +#define DPQ_NEXT( elem ) (elem).lpQNext + +#define DPQ_IS_ENDOFLIST( elem ) \ + ( DPQ_NEXT(elem) == NULL ) + +/* Insert element at end of queue */ #define DPQ_INSERT_IN_TAIL(head, elm, field) \ do { \ (elm)->field.lpQNext = NULL; \ @@ -41,6 +56,7 @@ do { \ (head).lpQHLast = &(elm)->field.lpQNext; \ } while(0) +/* Remove element from the queue */ #define DPQ_REMOVE(head, elm, field) \ do { \ if (((elm)->field.lpQNext) != NULL) \ @@ -53,18 +69,20 @@ do { \ /* head - pointer to DPQ_HEAD struct * elm - how to find the next element - * field - to be concatenated to rc to compare with fieldToEqual - * fieldToEqual - The value that we're looking for + * field - to be concatenated to rc to compare with fieldToCompare + * fieldToCompare - The value that we're comparing against + * fieldCompareOperator - The logical operator to compare field and + * fieldToCompare. * rc - Variable to put the return code. Same type as (head).lpQHFirst */ -#define DPQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc ) \ +#define DPQ_FIND_ENTRY( head, elm, field, fieldCompareOperator, fieldToCompare, rc )\ do { \ (rc) = (head).lpQHFirst; /* NULL head? */ \ \ while( rc ) \ { \ /* What we're searching for? */ \ - if( (rc)->field == (fieldToEqual) ) \ + if( (rc)->field fieldCompareOperator (fieldToCompare) ) \ { \ break; /* rc == correct element */ \ } \ @@ -81,12 +99,14 @@ do { \ /* head - pointer to DPQ_HEAD struct * elm - how to find the next element * field - to be concatenated to rc to compare with fieldToEqual - * fieldToEqual - The value that we're looking for + * fieldToCompare - The value that we're comparing against + * fieldCompareOperator - The logical operator to compare field and + * fieldToCompare. * rc - Variable to put the return code. Same type as (head).lpQHFirst */ -#define DPQ_REMOVE_ENTRY( head, elm, field, fieldToEqual, rc ) \ +#define DPQ_REMOVE_ENTRY( head, elm, field, fieldCompareOperator, fieldToCompare, rc )\ do { \ - DPQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc ); \ + DPQ_FIND_ENTRY( head, elm, field, fieldCompareOperator, fieldToCompare, rc );\ \ /* Was the element found? */ \ if( rc ) \ @@ -95,4 +115,24 @@ do { \ } \ } while(0) +/* Delete the entire queue + * head - pointer to the head of the queue + * field - field to access the next elements of the queue + * type - type of the pointer to the element element + * df - a delete function to be called. Declared with DPQ_DECL_DELETECB. + */ +#define DPQ_DELETEQ( head, field, type, df ) \ +while( !DPQ_IS_EMPTY(head) ) \ +{ \ + type holder = (head).lpQHFirst; \ + DPQ_REMOVE( head, holder, field ); \ + df( holder ); \ +} + +/* How to define the method to be passed to DPQ_DELETEQ */ +#define DPQ_DECL_DELETECB( name, type ) void name( type elem ) + +/* Prototype of a method which just performs a HeapFree on the elem */ +DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID ); + #endif /* __WINE_DPLAYX_QUEUE_H */ diff --git a/dlls/dplayx/dplobby.c b/dlls/dplayx/dplobby.c index 8507ccefdd2..3a451fefe41 100644 --- a/dlls/dplayx/dplobby.c +++ b/dlls/dplayx/dplobby.c @@ -5,8 +5,6 @@ * * */ -#include - #include "winerror.h" #include "winnt.h" #include "winreg.h" @@ -17,6 +15,7 @@ #include "dpinit.h" #include "dplayx_global.h" #include "dplayx_messages.h" +#include "dplayx_queue.h" DEFAULT_DEBUG_CHANNEL(dplay) @@ -39,13 +38,16 @@ HRESULT DPL_CreateAddress( REFGUID guidSP, REFGUID guidDataType, LPCVOID lpData, -static HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, +extern HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, DWORD dwAddressSize, LPVOID lpContext ); static HRESULT WINAPI DPL_ConnectEx( IDirectPlayLobbyAImpl* This, DWORD dwFlags, REFIID riid, LPVOID* lplpDP, IUnknown* pUnk ); +BOOL DPL_CreateAndSetLobbyHandles( DWORD dwDestProcessId, HANDLE hDestProcess, + LPHANDLE lphStart, LPHANDLE lphDeath, + LPHANDLE lphRead ); /***************************************************************************** @@ -61,16 +63,23 @@ static HRESULT WINAPI DPL_ConnectEx( IDirectPlayLobbyAImpl* This, * get a run time trap, as that won't have any data. * */ +struct DPLMSG +{ + DPQ_ENTRY( DPLMSG ) msgs; /* Link to next queued message */ +}; +typedef struct DPLMSG* LPDPLMSG; typedef struct tagDirectPlayLobbyIUnknownData { - DWORD ref; + ULONG ulObjRef; CRITICAL_SECTION DPL_lock; } DirectPlayLobbyIUnknownData; typedef struct tagDirectPlayLobbyData { HKEY hkCallbackKeyHack; + DWORD dwMsgThread; + DPQ_HEAD( DPLMSG ) msgs; /* List of messages received */ } DirectPlayLobbyData; typedef struct tagDirectPlayLobby2Data @@ -84,6 +93,7 @@ typedef struct tagDirectPlayLobby3Data } DirectPlayLobby3Data; #define DPL_IMPL_FIELDS \ + ULONG ulInterfaceRef; \ DirectPlayLobbyIUnknownData* unk; \ DirectPlayLobbyData* dpl; \ DirectPlayLobby2Data* dpl2; \ @@ -120,6 +130,112 @@ static ICOM_VTABLE(IDirectPlayLobby3) directPlayLobby3AVT; +static BOOL DPL_CreateIUnknown( LPVOID lpDPL ) +{ + ICOM_THIS(IDirectPlayLobbyAImpl,lpDPL); + + This->unk = (DirectPlayLobbyIUnknownData*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *(This->unk) ) ); + if ( This->unk == NULL ) + { + return FALSE; + } + + InitializeCriticalSection( &This->unk->DPL_lock ); + + return TRUE; +} + +static BOOL DPL_DestroyIUnknown( LPVOID lpDPL ) +{ + ICOM_THIS(IDirectPlayLobbyAImpl,lpDPL); + + DeleteCriticalSection( &This->unk->DPL_lock ); + HeapFree( GetProcessHeap(), 0, This->unk ); + + return TRUE; +} + +static BOOL DPL_CreateLobby1( LPVOID lpDPL ) +{ + ICOM_THIS(IDirectPlayLobbyAImpl,lpDPL); + + This->dpl = (DirectPlayLobbyData*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *(This->dpl) ) ); + if ( This->dpl == NULL ) + { + return FALSE; + } + + DPQ_INIT( This->dpl->msgs ); + + return TRUE; +} + +static BOOL DPL_DestroyLobby1( LPVOID lpDPL ) +{ + ICOM_THIS(IDirectPlayLobbyAImpl,lpDPL); + + if( This->dpl->dwMsgThread ) + { + FIXME( "Should kill the msg thread\n" ); + } + + DPQ_DELETEQ( This->dpl->msgs, msgs, LPDPLMSG, cbDeleteElemFromHeap ); + + /* Delete the contents */ + HeapFree( GetProcessHeap(), 0, This->dpl ); + + return TRUE; +} + +static BOOL DPL_CreateLobby2( LPVOID lpDPL ) +{ + ICOM_THIS(IDirectPlayLobby2AImpl,lpDPL); + + This->dpl2 = (DirectPlayLobby2Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *(This->dpl2) ) ); + if ( This->dpl2 == NULL ) + { + return FALSE; + } + + return TRUE; +} + +static BOOL DPL_DestroyLobby2( LPVOID lpDPL ) +{ + ICOM_THIS(IDirectPlayLobby2AImpl,lpDPL); + + HeapFree( GetProcessHeap(), 0, This->dpl2 ); + + return TRUE; +} + +static BOOL DPL_CreateLobby3( LPVOID lpDPL ) +{ + ICOM_THIS(IDirectPlayLobby3AImpl,lpDPL); + + This->dpl3 = (DirectPlayLobby3Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *(This->dpl3) ) ); + if ( This->dpl3 == NULL ) + { + return FALSE; + } + + return TRUE; +} + +static BOOL DPL_DestroyLobby3( LPVOID lpDPL ) +{ + ICOM_THIS(IDirectPlayLobby3AImpl,lpDPL); + + HeapFree( GetProcessHeap(), 0, This->dpl3 ); + + return TRUE; +} + + /* The COM interface for upversioning an interface * We've been given a GUID (riid) and we need to replace the present * interface with that of the requested interface. @@ -142,439 +258,162 @@ static ICOM_VTABLE(IDirectPlayLobby3) directPlayLobby3AVT; * queries successfully for a second, and through that pointer queries * successfully for a third interface, a query for the first interface * through the pointer for the third interface must succeed. - * - * As you can see, this interface doesn't qualify but will most likely - * be good enough for the time being. */ - - -BOOL DPL_CreateIUnknown( LPVOID lpDPL ) -{ - ICOM_THIS(IDirectPlayLobbyAImpl,lpDPL); - - This->unk = (DirectPlayLobbyIUnknownData*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( *(This->unk) ) ); - if ( This->unk == NULL ) - { - return FALSE; - } - - InitializeCriticalSection( &This->unk->DPL_lock ); - - IDirectPlayLobby_AddRef( (LPDIRECTPLAYLOBBYA)lpDPL ); - - return TRUE; -} - -BOOL DPL_DestroyIUnknown( LPVOID lpDPL ) -{ - ICOM_THIS(IDirectPlayLobbyAImpl,lpDPL); - - DeleteCriticalSection( &This->unk->DPL_lock ); - HeapFree( GetProcessHeap(), 0, This->unk ); - - return TRUE; -} - -BOOL DPL_CreateLobby1( LPVOID lpDPL ) -{ - ICOM_THIS(IDirectPlayLobbyAImpl,lpDPL); - - This->dpl = (DirectPlayLobbyData*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( *(This->dpl) ) ); - if ( This->dpl == NULL ) - { - return FALSE; - } - - return TRUE; -} - -BOOL DPL_DestroyLobby1( LPVOID lpDPL ) -{ - ICOM_THIS(IDirectPlayLobbyAImpl,lpDPL); - - /* Delete the contents */ - HeapFree( GetProcessHeap(), 0, This->dpl ); - - return TRUE; -} - -BOOL DPL_CreateLobby2( LPVOID lpDPL ) -{ - ICOM_THIS(IDirectPlayLobby2AImpl,lpDPL); - - This->dpl2 = (DirectPlayLobby2Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( *(This->dpl2) ) ); - if ( This->dpl2 == NULL ) - { - return FALSE; - } - - return TRUE; -} - -BOOL DPL_DestroyLobby2( LPVOID lpDPL ) -{ - ICOM_THIS(IDirectPlayLobby2AImpl,lpDPL); - - HeapFree( GetProcessHeap(), 0, This->dpl2 ); - - return TRUE; -} - -BOOL DPL_CreateLobby3( LPVOID lpDPL ) -{ - ICOM_THIS(IDirectPlayLobby3AImpl,lpDPL); - - This->dpl3 = (DirectPlayLobby3Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( *(This->dpl3) ) ); - if ( This->dpl3 == NULL ) - { - return FALSE; - } - - return TRUE; -} - -BOOL DPL_DestroyLobby3( LPVOID lpDPL ) -{ - ICOM_THIS(IDirectPlayLobby3AImpl,lpDPL); - - HeapFree( GetProcessHeap(), 0, This->dpl3 ); - - return TRUE; -} - - -/* Helper function for DirectPlayLobby QueryInterface */ extern -HRESULT directPlayLobby_QueryInterface +HRESULT DPL_CreateInterface ( REFIID riid, LPVOID* ppvObj ) { + TRACE( " for %s\n", debugstr_guid( riid ) ); + + *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( IDirectPlayLobbyWImpl ) ); + + if( *ppvObj == NULL ) + { + return DPERR_OUTOFMEMORY; + } + if( IsEqualGUID( &IID_IDirectPlayLobby, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlayLobbyWImpl ) ); - - if( *ppvObj == NULL ) - { - return E_OUTOFMEMORY; - } - - /* new scope for variable declaration */ - { - ICOM_THIS(IDirectPlayLobbyWImpl,*ppvObj); - - ICOM_VTBL(This) = &directPlayLobbyWVT; - - if ( DPL_CreateIUnknown( (LPVOID)This ) && - DPL_CreateLobby1( (LPVOID)This ) - ) - { - return S_OK; - } - - } - - goto error; + ICOM_THIS(IDirectPlayLobbyWImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobbyWVT; } else if( IsEqualGUID( &IID_IDirectPlayLobbyA, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlayLobbyAImpl ) ); - - if( *ppvObj == NULL ) - { - return E_OUTOFMEMORY; - } - - { - ICOM_THIS(IDirectPlayLobbyAImpl,*ppvObj); - - ICOM_VTBL(This) = &directPlayLobbyAVT; - - if ( DPL_CreateIUnknown( (LPVOID)This ) && - DPL_CreateLobby1( (LPVOID)This ) - ) - { - return S_OK; - } - } - - goto error; + ICOM_THIS(IDirectPlayLobbyAImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobbyAVT; } else if( IsEqualGUID( &IID_IDirectPlayLobby2, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlayLobby2WImpl ) ); - - if( *ppvObj == NULL ) - { - return E_OUTOFMEMORY; - } - - { - ICOM_THIS(IDirectPlayLobby2WImpl,*ppvObj); - - ICOM_VTBL(This) = &directPlayLobby2WVT; - - if ( DPL_CreateIUnknown( (LPVOID)This ) && - DPL_CreateLobby1( (LPVOID)This ) && - DPL_CreateLobby2( (LPVOID)This ) - ) - { - return S_OK; - } - } - - goto error; + ICOM_THIS(IDirectPlayLobby2WImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobby2WVT; } else if( IsEqualGUID( &IID_IDirectPlayLobby2A, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlayLobby2AImpl ) ); - - if( *ppvObj == NULL ) - { - return E_OUTOFMEMORY; - } - - { - ICOM_THIS(IDirectPlayLobby2AImpl,*ppvObj); - - ICOM_VTBL(This) = &directPlayLobby2AVT; - - if ( DPL_CreateIUnknown( (LPVOID)This ) && - DPL_CreateLobby1( (LPVOID)This ) && - DPL_CreateLobby2( (LPVOID)This ) - ) - { - return S_OK; - } - } - - goto error; + ICOM_THIS(IDirectPlayLobby2AImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobby2AVT; } else if( IsEqualGUID( &IID_IDirectPlayLobby3, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlayLobby3WImpl ) ); - - if( *ppvObj == NULL ) - { - return E_OUTOFMEMORY; - } - - { - ICOM_THIS(IDirectPlayLobby3WImpl,*ppvObj); - - ICOM_VTBL(This) = &directPlayLobby3WVT; - - if ( DPL_CreateIUnknown( *ppvObj ) && - DPL_CreateLobby1( *ppvObj ) && - DPL_CreateLobby2( *ppvObj ) && - DPL_CreateLobby3( *ppvObj ) - ) - { - return S_OK; - } - } - - goto error; + ICOM_THIS(IDirectPlayLobby3WImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobby3WVT; } else if( IsEqualGUID( &IID_IDirectPlayLobby3A, riid ) ) { - *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof( IDirectPlayLobby3AImpl ) ); + ICOM_THIS(IDirectPlayLobby3AImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobby3AVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; - if( *ppvObj == NULL ) - { - return E_OUTOFMEMORY; - } - - { - ICOM_THIS(IDirectPlayLobby3AImpl,*ppvObj); - - ICOM_VTBL(This) = &directPlayLobby3AVT; - - if ( DPL_CreateIUnknown( *ppvObj ) && - DPL_CreateLobby1( *ppvObj ) && - DPL_CreateLobby2( *ppvObj ) && - DPL_CreateLobby3( *ppvObj ) - ) - { - return S_OK; - } - } - - goto error; + return E_NOINTERFACE; + } + + /* Initialize it */ + if ( DPL_CreateIUnknown( *ppvObj ) && + DPL_CreateLobby1( *ppvObj ) && + DPL_CreateLobby2( *ppvObj ) && + DPL_CreateLobby3( *ppvObj ) + ) + { + IDirectPlayLobby_AddRef( (LPDIRECTPLAYLOBBY)*ppvObj ); + return S_OK; } - /* Unsupported interface */ + /* Initialize failed, destroy it */ + DPL_DestroyLobby3( *ppvObj ); + DPL_DestroyLobby2( *ppvObj ); + DPL_DestroyLobby1( *ppvObj ); + DPL_DestroyIUnknown( *ppvObj ); + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; - return E_NOINTERFACE; - -error: - - DPL_DestroyLobby3( *ppvObj ); - DPL_DestroyLobby2( *ppvObj ); - DPL_DestroyLobby1( *ppvObj ); - DPL_DestroyIUnknown( *ppvObj ); - HeapFree( GetProcessHeap(), 0, *ppvObj ); - - *ppvObj = NULL; - return DPERR_NOMEMORY; + return DPERR_NOMEMORY; } -static HRESULT WINAPI IDirectPlayLobbyAImpl_QueryInterface +static HRESULT WINAPI DPL_QueryInterface ( LPDIRECTPLAYLOBBYA iface, REFIID riid, LPVOID* ppvObj ) { ICOM_THIS(IDirectPlayLobbyAImpl,iface); - TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj ); + TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj ); - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlayLobbyA, riid ) - ) + *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( IDirectPlayLobbyWImpl ) ); + + if( *ppvObj == NULL ) { - IDirectPlayLobby_AddRef( iface ); - *ppvObj = This; - return S_OK; + return DPERR_OUTOFMEMORY; } - return directPlayLobby_QueryInterface( riid, ppvObj ); + CopyMemory( *ppvObj, iface, sizeof( IDirectPlayLobbyWImpl ) ); + (*(IDirectPlayLobbyWImpl**)ppvObj)->ulInterfaceRef = 0; -} - -static HRESULT WINAPI IDirectPlayLobbyW_QueryInterface -( LPDIRECTPLAYLOBBY iface, - REFIID riid, - LPVOID* ppvObj ) -{ - ICOM_THIS(IDirectPlayLobbyWImpl,iface); - TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj ); - - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlayLobby, riid ) - ) + if( IsEqualGUID( &IID_IDirectPlayLobby, riid ) ) { - IDirectPlayLobby_AddRef( iface ); - *ppvObj = This; - return S_OK; + ICOM_THIS(IDirectPlayLobbyWImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobbyWVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobbyA, riid ) ) + { + ICOM_THIS(IDirectPlayLobbyAImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobbyAVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby2, riid ) ) + { + ICOM_THIS(IDirectPlayLobby2WImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobby2WVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby2A, riid ) ) + { + ICOM_THIS(IDirectPlayLobby2AImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobby2AVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby3, riid ) ) + { + ICOM_THIS(IDirectPlayLobby3WImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobby3WVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby3A, riid ) ) + { + ICOM_THIS(IDirectPlayLobby3AImpl,*ppvObj); + ICOM_VTBL(This) = &directPlayLobby3AVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + return E_NOINTERFACE; } - return directPlayLobby_QueryInterface( riid, ppvObj ); -} - - -static HRESULT WINAPI IDirectPlayLobby2AImpl_QueryInterface -( LPDIRECTPLAYLOBBY2A iface, - REFIID riid, - LPVOID* ppvObj ) -{ - ICOM_THIS(IDirectPlayLobby2AImpl,iface); - TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj ); - - /* Compare riids. We know this object is a direct play lobby 2A object. - If we are asking about the same type of interface we're fine. - */ - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlayLobby2A, riid ) - ) - { - IDirectPlayLobby_AddRef( iface ); - *ppvObj = This; - return S_OK; - } - return directPlayLobby_QueryInterface( riid, ppvObj ); -} - -static HRESULT WINAPI IDirectPlayLobby2WImpl_QueryInterface -( LPDIRECTPLAYLOBBY2 iface, - REFIID riid, - LPVOID* ppvObj ) -{ - ICOM_THIS(IDirectPlayLobby2WImpl,iface); - - /* Compare riids. We know this object is a direct play lobby 2 object. - If we are asking about the same type of interface we're fine. - */ - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlayLobby2, riid ) - ) - { - IDirectPlayLobby_AddRef( iface ); - *ppvObj = This; - return S_OK; - } - - return directPlayLobby_QueryInterface( riid, ppvObj ); - -} - -static HRESULT WINAPI IDirectPlayLobby3AImpl_QueryInterface -( LPDIRECTPLAYLOBBY3A iface, - REFIID riid, - LPVOID* ppvObj ) -{ - ICOM_THIS(IDirectPlayLobby3AImpl,iface); - - /* Compare riids. We know this object is a direct play lobby 3 object. - If we are asking about the same type of interface we're fine. - */ - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlayLobby3A, riid ) - ) - { - IDirectPlayLobby_AddRef( iface ); - *ppvObj = This; - return S_OK; - } - - return directPlayLobby_QueryInterface( riid, ppvObj ); - -} - -static HRESULT WINAPI IDirectPlayLobby3WImpl_QueryInterface -( LPDIRECTPLAYLOBBY3 iface, - REFIID riid, - LPVOID* ppvObj ) -{ - ICOM_THIS(IDirectPlayLobby3WImpl,iface); - - /* Compare riids. We know this object is a direct play lobby 3 object. - If we are asking about the same type of interface we're fine. - */ - if( IsEqualGUID( &IID_IUnknown, riid ) || - IsEqualGUID( &IID_IDirectPlayLobby3, riid ) - ) - { - IDirectPlayLobby_AddRef( iface ); - *ppvObj = This; - return S_OK; - } - - return directPlayLobby_QueryInterface( riid, ppvObj ); + IDirectPlayLobby_AddRef( (LPDIRECTPLAYLOBBY)*ppvObj ); + return S_OK; } /* * Simple procedure. Just increment the reference count to this * structure and return the new reference count. */ -static ULONG WINAPI IDirectPlayLobbyImpl_AddRef +static ULONG WINAPI DPL_AddRef ( LPDIRECTPLAYLOBBY iface ) { - ULONG refCount; + ULONG ulInterfaceRefCount, ulObjRefCount; ICOM_THIS(IDirectPlayLobbyWImpl,iface); - refCount = InterlockedIncrement( &This->unk->ref ); + ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef ); + ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef ); - TRACE("ref count incremented to %lu for %p\n", refCount, This ); + TRACE( "ref count incremented to %lu:%lu for %p\n", + ulInterfaceRefCount, ulObjRefCount, This ); - return refCount; + return ulObjRefCount; } /* @@ -582,27 +421,33 @@ static ULONG WINAPI IDirectPlayLobbyImpl_AddRef * If the object no longer has any reference counts, free up the associated * memory. */ -static ULONG WINAPI IDirectPlayLobbyAImpl_Release +static ULONG WINAPI DPL_Release ( LPDIRECTPLAYLOBBYA iface ) { - ULONG refCount; + ULONG ulInterfaceRefCount, ulObjRefCount; ICOM_THIS(IDirectPlayLobbyAImpl,iface); - refCount = InterlockedDecrement( &This->unk->ref ); + ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef ); + ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef ); - TRACE("ref count decremeneted to %lu for %p\n", refCount, This ); + TRACE( "ref count decremented to %lu:%lu for %p\n", + ulInterfaceRefCount, ulObjRefCount, This ); /* Deallocate if this is the last reference to the object */ - if( refCount ) + if( ulObjRefCount == 0 ) { DPL_DestroyLobby3( This ); DPL_DestroyLobby2( This ); DPL_DestroyLobby1( This ); DPL_DestroyIUnknown( This ); - HeapFree( GetProcessHeap(), 0, This ); } - return refCount; + if( ulInterfaceRefCount == 0 ) + { + HeapFree( GetProcessHeap(), 0, This ); + } + + return ulInterfaceRefCount; } @@ -628,25 +473,25 @@ static HRESULT WINAPI DPL_ConnectEx FIXME("(%p)->(0x%08lx,%p,%p): semi stub\n", This, dwFlags, lplpDP, pUnk ); - if( dwFlags || pUnk ) + if( pUnk ) { return DPERR_INVALIDPARAMS; } + /* Backwards compatibility */ + if( dwFlags == 0 ) + { + dwFlags = DPCONNECT_RETURNSTATUS; + } + /* Create the DirectPlay interface */ - if( ( hr = directPlay_QueryInterface( riid, lplpDP ) ) != DP_OK ) + if( ( hr = DP_CreateInterface( riid, lplpDP ) ) != DP_OK ) { ERR( "error creating interface for %s:%s.\n", debugstr_guid( riid ), DPLAYX_HresultToString( hr ) ); return hr; } - /* - Need to call IDirectPlay::EnumConnections with the service provider to get that good information - * - Need to call CreateAddress to create the lpConnection param for IDirectPlay::InitializeConnection - * - Call IDirectPlay::InitializeConnection - * - Call IDirectPlay::Open - */ - /* FIXME: Is it safe/correct to use appID of 0? */ hr = IDirectPlayLobby_GetConnectionSettings( (LPDIRECTPLAYLOBBY)This, 0, NULL, &dwConnSize ); @@ -670,6 +515,17 @@ static HRESULT WINAPI DPL_ConnectEx return hr; } +#if 0 + /* - Need to call IDirectPlay::EnumConnections with the service provider to get that good information + * - Need to call CreateAddress to create the lpConnection param for IDirectPlay::InitializeConnection + * - Call IDirectPlay::InitializeConnection + */ + + /* Now initialize the Service Provider */ + hr = IDirectPlayX_InitializeConnection( (*(LPDIRECTPLAY2*)lplpDP), +#endif + + /* Setup flags to pass into DirectPlay::Open */ if( dwFlags & DPCONNECT_RETURNSTATUS ) { @@ -811,7 +667,7 @@ static HRESULT WINAPI IDirectPlayLobbyWImpl_EnumAddress return DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext ); } -static HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, +extern HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, DWORD dwAddressSize, LPVOID lpContext ) { DWORD dwTotalSizeEnumerated = 0; @@ -824,14 +680,16 @@ static HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, L DWORD dwSizeThisEnumeration; /* Invoke the enum method. If false is returned, stop enumeration */ - if ( !lpEnumAddressCallback( &lpElements->guidDataType, lpElements->dwDataSize, - lpElements + sizeof( DPADDRESS ), lpContext ) ) + if ( !lpEnumAddressCallback( &lpElements->guidDataType, + lpElements->dwDataSize, + (BYTE*)lpElements + sizeof( DPADDRESS ), + lpContext ) ) { break; } dwSizeThisEnumeration = sizeof( DPADDRESS ) + lpElements->dwDataSize; - lpAddress = (char *) lpAddress + dwSizeThisEnumeration; + lpAddress = (BYTE*) lpAddress + dwSizeThisEnumeration; dwTotalSizeEnumerated += dwSizeThisEnumeration; } @@ -1113,7 +971,6 @@ static HRESULT WINAPI IDirectPlayLobbyAImpl_GetConnectionSettings { ICOM_THIS(IDirectPlayLobbyAImpl,iface); HRESULT hr; - BOOL bSendHaveReadSettingsMessage = FALSE; TRACE("(%p)->(0x%08lx,%p,%p)\n", This, dwAppID, lpData, lpdwDataSize ); @@ -1121,17 +978,11 @@ static HRESULT WINAPI IDirectPlayLobbyAImpl_GetConnectionSettings hr = DPLAYX_GetConnectionSettingsA( dwAppID, lpData, - lpdwDataSize, - &bSendHaveReadSettingsMessage + lpdwDataSize ); LeaveCriticalSection( &This->unk->DPL_lock ); - if( bSendHaveReadSettingsMessage ) - { - FIXME( "Send a DPSYS_CONNECTIONSETTINGSREAD message\n" ); - } - return hr; } @@ -1143,7 +994,6 @@ static HRESULT WINAPI IDirectPlayLobbyWImpl_GetConnectionSettings { ICOM_THIS(IDirectPlayLobbyWImpl,iface); HRESULT hr; - BOOL bSendHaveReadSettingsMessage = FALSE; TRACE("(%p)->(0x%08lx,%p,%p)\n", This, dwAppID, lpData, lpdwDataSize ); @@ -1151,17 +1001,11 @@ static HRESULT WINAPI IDirectPlayLobbyWImpl_GetConnectionSettings hr = DPLAYX_GetConnectionSettingsW( dwAppID, lpData, - lpdwDataSize, - &bSendHaveReadSettingsMessage + lpdwDataSize ); LeaveCriticalSection( &This->unk->DPL_lock ); - if( bSendHaveReadSettingsMessage ) - { - FIXME( "Send a DPSYS_CONNECTIONSETTINGSREAD message\n" ); - } - return hr; } @@ -1288,6 +1132,54 @@ static BOOL CALLBACK RunApplicationA_EnumLocalApplications return TRUE; /* Keep enumerating, haven't found the application yet */ } +BOOL DPL_CreateAndSetLobbyHandles( DWORD dwDestProcessId, HANDLE hDestProcess, + LPHANDLE lphStart, LPHANDLE lphDeath, + LPHANDLE lphRead ) +{ + /* These are the handles for the created process */ + HANDLE hAppStart, hAppDeath, hAppRead, hTemp; + SECURITY_ATTRIBUTES s_attrib; + + s_attrib.nLength = sizeof( s_attrib ); + s_attrib.lpSecurityDescriptor = NULL; + s_attrib.bInheritHandle = TRUE; + + /* FIXME: Is there a handle leak here? */ + 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, + 0, FALSE, DUPLICATE_SAME_ACCESS ) ) || + ( !DuplicateHandle( GetCurrentProcess(), *lphDeath, + hDestProcess, &hAppDeath, + 0, FALSE, DUPLICATE_SAME_ACCESS ) ) || + ( !DuplicateHandle( GetCurrentProcess(), *lphRead, + hDestProcess, &hAppRead, + 0, FALSE, DUPLICATE_SAME_ACCESS ) ) + ) + { + /* FIXME: Handle leak... */ + ERR( "Unable to dup handles\n" ); + return FALSE; + } + + if( !DPLAYX_SetLobbyHandles( dwDestProcessId, + hAppStart, hAppDeath, hAppRead ) ) + { + return FALSE; + } + + return TRUE; +} + + /******************************************************************** * * Starts an application and passes to it all the information to @@ -1309,8 +1201,10 @@ static HRESULT WINAPI IDirectPlayLobbyAImpl_RunApplication PROCESS_INFORMATION newProcessInfo; LPSTR appName; DWORD dwSuspendCount; + HANDLE hStart, hDeath, hSettingRead; - TRACE( "(%p)->(0x%08lx,%p,%p,%x)\n", This, dwFlags, lpdwAppID, lpConn, hReceiveEvent ); + TRACE( "(%p)->(0x%08lx,%p,%p,%x)\n", + This, dwFlags, lpdwAppID, lpConn, hReceiveEvent ); if( dwFlags != 0 ) { @@ -1380,7 +1274,7 @@ static HRESULT WINAPI IDirectPlayLobbyAImpl_RunApplication HeapFree( GetProcessHeap(), 0, enumData.lpszCurrentDirectory ); /* Reserve this global application id! */ - if( !DPLAYX_CreateLobbyApplication( newProcessInfo.dwProcessId, hReceiveEvent ) ) + if( !DPLAYX_CreateLobbyApplication( newProcessInfo.dwProcessId ) ) { ERR( "Unable to create global application data for 0x%08lx\n", newProcessInfo.dwProcessId ); @@ -1394,17 +1288,22 @@ static HRESULT WINAPI IDirectPlayLobbyAImpl_RunApplication return hr; } - /* Everything seems to have been set correctly, update the dwAppID */ - *lpdwAppID = newProcessInfo.dwProcessId; + /* Setup the handles for application notification */ + DPL_CreateAndSetLobbyHandles( newProcessInfo.dwProcessId, + newProcessInfo.hProcess, + &hStart, &hDeath, &hSettingRead ); - if( hReceiveEvent ) - { - FIXME( "Need to store msg thread id\n" ); - CreateMessageReceptionThread( hReceiveEvent ); - } + /* Setup the message thread ID */ + This->dpl->dwMsgThread = + CreateLobbyMessageReceptionThread( hReceiveEvent, hStart, hDeath, hSettingRead ); + + DPLAYX_SetLobbyMsgThreadId( newProcessInfo.dwProcessId, This->dpl->dwMsgThread ); LeaveCriticalSection( &This->unk->DPL_lock ); + /* Everything seems to have been set correctly, update the dwAppID */ + *lpdwAppID = newProcessInfo.dwProcessId; + /* Unsuspend the process - should return the prev suspension count */ if( ( dwSuspendCount = ResumeThread( newProcessInfo.hThread ) ) != 1 ) { @@ -1481,8 +1380,11 @@ static HRESULT WINAPI IDirectPlayLobbyWImpl_SetConnectionSettings if( hr == DPERR_NOTLOBBIED ) { FIXME( "Unlobbied app setting connections. Is this correct behavior?\n" ); - dwAppID = GetCurrentProcessId(); - DPLAYX_CreateLobbyApplication( dwAppID, 0 ); + if( dwAppID == 0 ) + { + dwAppID = GetCurrentProcessId(); + } + DPLAYX_CreateLobbyApplication( dwAppID ); hr = DPLAYX_SetConnectionSettingsW( dwFlags, dwAppID, lpConn ); } @@ -1513,7 +1415,7 @@ static HRESULT WINAPI IDirectPlayLobbyAImpl_SetConnectionSettings { FIXME( "Unlobbied app setting connections. Is this correct behavior?\n" ); dwAppID = GetCurrentProcessId(); - DPLAYX_CreateLobbyApplication( dwAppID, 0 ); + DPLAYX_CreateLobbyApplication( dwAppID ); hr = DPLAYX_SetConnectionSettingsA( dwFlags, dwAppID, lpConn ); } @@ -1658,7 +1560,7 @@ HRESULT DPL_CreateCompoundAddress { LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; - lpdpAddress->guidDataType = DPAID_TotalSize; + CopyMemory( &lpdpAddress->guidDataType, &DPAID_TotalSize, sizeof( GUID ) ); lpdpAddress->dwDataSize = sizeof( DWORD ); lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); @@ -1677,11 +1579,12 @@ HRESULT DPL_CreateCompoundAddress { LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; - lpdpAddress->guidDataType = lpElements->guidDataType; + CopyMemory( &lpdpAddress->guidDataType, &lpElements->guidDataType, + sizeof( GUID ) ); lpdpAddress->dwDataSize = sizeof( GUID ); lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); - *((LPGUID)lpAddress) = *((LPGUID)lpElements->lpData); + CopyMemory( lpAddress, lpElements->lpData, sizeof( GUID ) ); lpAddress = (char *) lpAddress + sizeof( GUID ); } else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Phone ) ) || @@ -1691,7 +1594,8 @@ HRESULT DPL_CreateCompoundAddress { LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; - lpdpAddress->guidDataType = lpElements->guidDataType; + CopyMemory( &lpdpAddress->guidDataType, &lpElements->guidDataType, + sizeof( GUID ) ); lpdpAddress->dwDataSize = lpElements->dwDataSize; lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); @@ -1707,7 +1611,8 @@ HRESULT DPL_CreateCompoundAddress { LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; - lpdpAddress->guidDataType = lpElements->guidDataType; + CopyMemory( &lpdpAddress->guidDataType, &lpElements->guidDataType, + sizeof( GUID ) ); lpdpAddress->dwDataSize = lpElements->dwDataSize; lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); @@ -1720,7 +1625,8 @@ HRESULT DPL_CreateCompoundAddress { LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; - lpdpAddress->guidDataType = lpElements->guidDataType; + CopyMemory( &lpdpAddress->guidDataType, &lpElements->guidDataType, + sizeof( GUID ) ); lpdpAddress->dwDataSize = lpElements->dwDataSize; lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); @@ -1731,11 +1637,12 @@ HRESULT DPL_CreateCompoundAddress { LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; - lpdpAddress->guidDataType = lpElements->guidDataType; + CopyMemory( &lpdpAddress->guidDataType, &lpElements->guidDataType, + sizeof( GUID ) ); lpdpAddress->dwDataSize = lpElements->dwDataSize; lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); - memcpy( lpAddress, lpElements->lpData, sizeof( DPADDRESS ) ); + CopyMemory( lpAddress, lpElements->lpData, sizeof( DPADDRESS ) ); lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); } } @@ -1839,9 +1746,9 @@ static struct ICOM_VTABLE(IDirectPlayLobby) directPlayLobbyAVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - IDirectPlayLobbyAImpl_QueryInterface, - XCAST(AddRef)IDirectPlayLobbyImpl_AddRef, - XCAST(Release)IDirectPlayLobbyAImpl_Release, + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, IDirectPlayLobbyAImpl_Connect, IDirectPlayLobbyAImpl_CreateAddress, @@ -1870,9 +1777,9 @@ static ICOM_VTABLE(IDirectPlayLobby) directPlayLobbyWVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - IDirectPlayLobbyW_QueryInterface, - XCAST(AddRef)IDirectPlayLobbyImpl_AddRef, - XCAST(Release)IDirectPlayLobbyAImpl_Release, + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, IDirectPlayLobbyWImpl_Connect, IDirectPlayLobbyWImpl_CreateAddress, @@ -1900,9 +1807,9 @@ static ICOM_VTABLE(IDirectPlayLobby2) directPlayLobby2AVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - IDirectPlayLobby2AImpl_QueryInterface, - XCAST(AddRef)IDirectPlayLobbyImpl_AddRef, - XCAST(Release)IDirectPlayLobbyAImpl_Release, + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, XCAST(Connect)IDirectPlayLobbyAImpl_Connect, XCAST(CreateAddress)IDirectPlayLobbyAImpl_CreateAddress, @@ -1932,9 +1839,9 @@ static ICOM_VTABLE(IDirectPlayLobby2) directPlayLobby2WVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - IDirectPlayLobby2WImpl_QueryInterface, - XCAST(AddRef)IDirectPlayLobbyImpl_AddRef, - XCAST(Release)IDirectPlayLobbyAImpl_Release, + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, XCAST(Connect)IDirectPlayLobbyWImpl_Connect, XCAST(CreateAddress)IDirectPlayLobbyWImpl_CreateAddress, @@ -1964,9 +1871,9 @@ static ICOM_VTABLE(IDirectPlayLobby2) directPlayLobby2WVT = static ICOM_VTABLE(IDirectPlayLobby3) directPlayLobby3AVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - IDirectPlayLobby3AImpl_QueryInterface, - XCAST(AddRef)IDirectPlayLobbyImpl_AddRef, - XCAST(Release)IDirectPlayLobbyAImpl_Release, + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, XCAST(Connect)IDirectPlayLobbyAImpl_Connect, XCAST(CreateAddress)IDirectPlayLobbyAImpl_CreateAddress, @@ -2001,9 +1908,9 @@ static ICOM_VTABLE(IDirectPlayLobby3) directPlayLobby3AVT = static ICOM_VTABLE(IDirectPlayLobby3) directPlayLobby3WVT = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - IDirectPlayLobby3WImpl_QueryInterface, - XCAST(AddRef)IDirectPlayLobbyImpl_AddRef, - XCAST(Release)IDirectPlayLobbyAImpl_Release, + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, XCAST(Connect)IDirectPlayLobbyWImpl_Connect, XCAST(CreateAddress)IDirectPlayLobbyWImpl_CreateAddress, @@ -2029,7 +1936,7 @@ static ICOM_VTABLE(IDirectPlayLobby3) directPlayLobby3WVT = /********************************************************* * - * Direct Play and Direct Play Lobby Interface Implementation + * Direct Play Lobby Interface Implementation * *********************************************************/ @@ -2049,13 +1956,20 @@ HRESULT WINAPI DirectPlayLobbyCreateA( LPGUID lpGUIDDSP, /* Parameter Check: lpGUIDSP, lpUnk & lpData must be NULL. dwDataSize must * equal 0. These fields are mostly for future expansion. */ - if ( lpGUIDDSP || lpUnk || lpData || dwDataSize ) + if ( lpGUIDDSP || lpData || dwDataSize ) { *lplpDPL = NULL; return DPERR_INVALIDPARAMS; } - return directPlayLobby_QueryInterface( &IID_IDirectPlayLobbyA, (void**)lplpDPL ); + if( lpUnk ) + { + *lplpDPL = NULL; + ERR("Bad parameters!\n" ); + return CLASS_E_NOAGGREGATION; + } + + return DPL_CreateInterface( &IID_IDirectPlayLobbyA, (void**)lplpDPL ); } /*************************************************************************** @@ -2088,6 +2002,5 @@ HRESULT WINAPI DirectPlayLobbyCreateW( LPGUID lpGUIDDSP, return CLASS_E_NOAGGREGATION; } - return directPlayLobby_QueryInterface( &IID_IDirectPlayLobby, (void**)lplpDPL ); - + return DPL_CreateInterface( &IID_IDirectPlayLobby, (void**)lplpDPL ); } diff --git a/dlls/dplayx/name_server.c b/dlls/dplayx/name_server.c index d81ad5721db..07a66dcadc5 100644 --- a/dlls/dplayx/name_server.c +++ b/dlls/dplayx/name_server.c @@ -10,101 +10,190 @@ #include "winbase.h" #include "debugtools.h" +#include "heap.h" #include "dplayx_global.h" #include "name_server.h" +#include "dplaysp.h" +#include "dplayx_messages.h" +#include "dplayx_queue.h" -/* FIXME: Need to aquire the interface semaphore before didlling data */ +/* Can't seem to solve unresolved reference even with import */ +#define HACK_TIMEGETTIME + +#if defined( HACK_TIMEGETTIME ) +static DWORD timeGetTime(void); +#else +#include "mmsystem.h" +#endif + +/* FIXME: Need to create a crit section, store and use it */ DEFAULT_DEBUG_CHANNEL(dplay); /* NS specific structures */ -typedef struct tagNSCacheData +struct NSCacheData { - struct tagNSCacheData* next; + DPQ_ENTRY(NSCacheData) next; + DWORD dwTime; /* Time at which data was last known valid */ LPDPSESSIONDESC2 data; -} NSCacheData, *lpNSCacheData; + LPVOID lpNSAddrHdr; -typedef struct tagNSCache +}; +typedef struct NSCacheData NSCacheData, *lpNSCacheData; + +struct NSCache { - lpNSCacheData present; /* keep track of what is to be looked at */ - lpNSCacheData first; -} NSCache, *lpNSCache; - -/* Local Prototypes */ -static void NS_InvalidateSessionCache( lpNSCache lpCache ); + lpNSCacheData present; /* keep track of what is to be looked at when walking */ + DPQ_HEAD(NSCacheData) first; +}; +typedef struct NSCache NSCache, *lpNSCache; /* Name Server functions * --------------------- */ void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd ) { +#if 0 DPLAYX_SetLocalSession( lpsd ); +#endif +} + +/* Store the given NS remote address for future reference */ +void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr, + DWORD dwHdrSize, + LPDPMSG_ENUMSESSIONSREPLY lpMsg, + LPVOID lpNSInfo ) +{ + lpNSCache lpCache = (lpNSCache)lpNSInfo; + lpNSCacheData lpCacheNode; + + TRACE( "%p, %p, %p\n", lpNSAddrHdr, lpMsg, lpNSInfo ); + + /* FIXME: Should check to see if the reply is for an existing session. If + * so we just update the contents and update the timestamp. + */ + lpCacheNode = (lpNSCacheData)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *lpCacheNode ) ); + + if( lpCacheNode == NULL ) + { + ERR( "no memory for NS node\n" ); + return; + } + + lpCacheNode->lpNSAddrHdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + dwHdrSize ); + CopyMemory( lpCacheNode->lpNSAddrHdr, lpNSAddrHdr, dwHdrSize ); + + + lpCacheNode->data = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof( *lpCacheNode->data ) ); + + if( lpCacheNode->data == NULL ) + { + ERR( "no memory for SESSIONDESC2\n" ); + return; + } + + CopyMemory( lpCacheNode->data, &lpMsg->sd, sizeof( *lpCacheNode->data ) ); + lpCacheNode->data->sess.lpszSessionNameA = HEAP_strdupWtoA( GetProcessHeap(), + HEAP_ZERO_MEMORY, + (LPWSTR)(lpMsg+1) ); + + lpCacheNode->dwTime = timeGetTime(); + + DPQ_INSERT(lpCache->first, lpCacheNode, next ); + + lpCache->present = lpCacheNode; + + /* Use this message as an oportunity to weed out any old sessions so + * that we don't enum them again + */ + NS_PruneSessionCache( lpNSInfo ); +} + +LPVOID NS_GetNSAddr( LPVOID lpNSInfo ) +{ + lpNSCache lpCache = (lpNSCache)lpNSInfo; + + FIXME( ":quick stub\n" ); + + /* Ok. Cheat and don't search for the correct stuff just take the first. + * FIXME: In the future how are we to know what is _THE_ enum we used? + */ + + return lpCache->first.lpQHFirst->lpNSAddrHdr; } /* This function is responsible for sending a request for all other known nameservers to send us what sessions they have registered locally */ -void NS_SendSessionRequestBroadcast( LPVOID lpNSInfo ) +HRESULT NS_SendSessionRequestBroadcast( LPCGUID lpcGuid, + DWORD dwFlags, + LPSPINITDATA lpSpData ) + { - UINT index = 0; - lpNSCache lpCache = (lpNSCache)lpNSInfo; - LPDPSESSIONDESC2 lpTmp = NULL; + DPSP_ENUMSESSIONSDATA data; + LPDPMSG_ENUMSESSIONSREQUEST lpMsg; - /* Invalidate the session cache for the interface */ - NS_InvalidateSessionCache( lpCache ); - - /* Add the local known sessions to the cache */ - if( ( lpTmp = DPLAYX_CopyAndAllocateLocalSession( &index ) ) != NULL ) - { - lpCache->first = (lpNSCacheData)HeapAlloc( GetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof( *(lpCache->first) ) ); - lpCache->first->data = lpTmp; - lpCache->first->next = NULL; - lpCache->present = lpCache->first; + TRACE( "enumerating for guid %s\n", debugstr_guid( lpcGuid ) ); - while( ( lpTmp = DPLAYX_CopyAndAllocateLocalSession( &index ) ) != NULL ) - { - lpCache->present->next = (lpNSCacheData)HeapAlloc( GetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof( *(lpCache->present) ) ); - lpCache->present = lpCache->present->next; - lpCache->present->data = lpTmp; - lpCache->present->next = NULL; - } + /* Get the SP to deal with sending the EnumSessions request */ + FIXME( ": not all data fields are correct\n" ); - lpCache->present = lpCache->first; - } + data.dwMessageSize = lpSpData->dwSPHeaderSize + sizeof( *lpMsg ); /*FIXME!*/ + data.lpMessage = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + data.dwMessageSize ); + data.lpISP = lpSpData->lpISP; + data.bReturnStatus = (dwFlags & DPENUMSESSIONS_RETURNSTATUS) ? TRUE : FALSE; - /* Send out requests for matching sessions to all other known computers */ - FIXME( ": no remote requests sent\n" ); - /* FIXME - how to handle responses to messages anyways? */ + + lpMsg = (LPDPMSG_ENUMSESSIONSREQUEST)(((BYTE*)data.lpMessage)+lpSpData->dwSPHeaderSize); + + /* Setup EnumSession reqest message */ + lpMsg->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG; + lpMsg->envelope.wCommandId = DPMSGCMD_ENUMSESSIONSREQUEST; + lpMsg->envelope.wVersion = DPMSGVER_DP6; + + lpMsg->dwPasswordSize = 0; /* FIXME: If enumerating passwords..? */ + lpMsg->dwFlags = dwFlags; + + CopyMemory( &lpMsg->guidApplication, lpcGuid, sizeof( *lpcGuid ) ); + + return (lpSpData->lpCB->EnumSessions)( &data ); } -/* Render all data in a session cache invalid */ -static void NS_InvalidateSessionCache( lpNSCache lpCache ) +DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData ); +DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData ) { + /* FIXME: Memory leak on data (contained ptrs) */ + HeapFree( GetProcessHeap(), 0, elem->data ); + HeapFree( GetProcessHeap(), 0, elem->lpNSAddrHdr ); + HeapFree( GetProcessHeap(), 0, elem ); +} + + + +/* Render all data in a session cache invalid */ +void NS_InvalidateSessionCache( LPVOID lpNSInfo ) +{ + lpNSCache lpCache = (lpNSCache)lpNSInfo; + if( lpCache == NULL ) { ERR( ": invalidate non existant cache\n" ); return; } - /* Remove everything from the cache */ - while( lpCache->first ) - { - lpCache->present = lpCache->first; - lpCache->first = lpCache->first->next; - HeapFree( GetProcessHeap(), 0, lpCache->present ); - } + DPQ_DELETEQ( lpCache->first, next, lpNSCacheData, cbDeleteNSNodeFromHeap ); - /* NULL out the cache pointers */ + /* NULL out the walking pointer */ lpCache->present = NULL; - lpCache->first = NULL; } /* Create and initialize a session cache */ @@ -121,7 +210,8 @@ BOOL NS_InitializeSessionCache( LPVOID* lplpNSInfo ) return FALSE; } - lpCache->first = lpCache->present = NULL; + DPQ_INIT(lpCache->first); + lpCache->present = NULL; return TRUE; } @@ -136,7 +226,7 @@ void NS_DeleteSessionCache( LPVOID lpNSInfo ) void NS_ResetSessionEnumeration( LPVOID lpNSInfo ) { - ((lpNSCache)lpNSInfo)->present = ((lpNSCache)lpNSInfo)->first; + ((lpNSCache)lpNSInfo)->present = ((lpNSCache)lpNSInfo)->first.lpQHFirst; } LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo ) @@ -144,6 +234,8 @@ LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo ) LPDPSESSIONDESC2 lpSessionDesc; lpNSCache lpCache = (lpNSCache)lpNSInfo; + /* FIXME: The pointers could disappear when walking if a prune happens */ + /* Test for end of the list */ if( lpCache->present == NULL ) { @@ -153,7 +245,93 @@ LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo ) lpSessionDesc = lpCache->present->data; /* Advance tracking pointer */ - lpCache->present = lpCache->present->next; + lpCache->present = lpCache->present->next.lpQNext; return lpSessionDesc; } + +/* This method should check to see if there are any sessions which are + * older than the criteria. If so, just delete that information. + */ +void NS_PruneSessionCache( LPVOID lpNSInfo ) +{ + lpNSCache lpCache = lpNSInfo; + lpNSCacheData lpCacheEntry; + + DWORD dwPresentTime = timeGetTime(); +#if defined( HACK_TIMEGETTIME ) + DWORD dwPruneTime = dwPresentTime - 2; /* One iteration with safety */ +#else + DWORD dwPruneTime = dwPresentTime - 10000 /* 10 secs? */; +#endif + + FIXME( ": semi stub\n" ); + + /* FIXME: This doesn't handle time roll over correctly */ + /* FIXME: Session memory leak on delete */ + do + { + DPQ_FIND_ENTRY( lpCache->first, next, dwTime, <=, dwPruneTime, lpCacheEntry ); + } + while( lpCacheEntry != NULL ); + +} + + + +/* Message stuff */ +void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg, + LPDPSP_REPLYDATA lpReplyData, + IDirectPlay2Impl* lpDP ) +{ + LPDPMSG_ENUMSESSIONSREPLY rmsg; + DWORD dwVariableSize; + DWORD dwVariableLen; + LPWSTR string; + /* LPDPMSG_ENUMSESSIONSREQUEST msg = (LPDPMSG_ENUMSESSIONSREQUEST)lpMsg; */ + BOOL bAnsi = TRUE; /* FIXME: This needs to be in the DPLAY interface */ + + FIXME( ": few fixed + need to check request for response\n" ); + + dwVariableLen = bAnsi ? lstrlenA( lpDP->dp2->lpSessionDesc->sess.lpszSessionNameA ) + 1 + : lstrlenW( lpDP->dp2->lpSessionDesc->sess.lpszSessionName ) + 1; + + dwVariableSize = dwVariableLen * sizeof( WCHAR ); + + lpReplyData->dwMessageSize = lpDP->dp2->spData.dwSPHeaderSize + + sizeof( *rmsg ) + dwVariableSize; + lpReplyData->lpMessage = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + lpReplyData->dwMessageSize ); + + rmsg = (LPDPMSG_ENUMSESSIONSREPLY)lpReplyData->lpMessage; + + rmsg->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG; + rmsg->envelope.wCommandId = DPMSGCMD_ENUMSESSIONSREPLY; + rmsg->envelope.wVersion = DPMSGVER_DP6; + + CopyMemory( &rmsg->sd, lpDP->dp2->lpSessionDesc, + sizeof( lpDP->dp2->lpSessionDesc->dwSize ) ); + rmsg->dwUnknown = 0x0000005c; + if( bAnsi ) + { + string = HEAP_strdupAtoW( GetProcessHeap(), 0, + lpDP->dp2->lpSessionDesc->sess.lpszSessionNameA ); + /* FIXME: Memory leak */ + } + else + { + string = lpDP->dp2->lpSessionDesc->sess.lpszSessionName; + } + + lstrcpyW( (LPWSTR)rmsg+1, string ); + +} + +#if defined( HACK_TIMEGETTIME ) +DWORD timeGetTime(void) +{ + static DWORD time = 0; + + return time++; +} +#endif diff --git a/dlls/dplayx/name_server.h b/dlls/dplayx/name_server.h index 33c27ac053b..9c500cda31a 100644 --- a/dlls/dplayx/name_server.h +++ b/dlls/dplayx/name_server.h @@ -3,14 +3,33 @@ #define __WINE_DPLAYX_NAMESERVER #include "dplay.h" +#include "dplaysp.h" +#include "dplayx_messages.h" +#include "dplay_global.h" void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd ); -void NS_SendSessionRequestBroadcast( LPVOID lpNSInfo ); +void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr, + DWORD dwHdrSize, + LPDPMSG_ENUMSESSIONSREPLY lpMsg, + LPVOID lpNSInfo ); +LPVOID NS_GetNSAddr( LPVOID lpNSInfo ); + +void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg, + LPDPSP_REPLYDATA lpReplyData, + IDirectPlay2Impl* lpDP ); + +HRESULT NS_SendSessionRequestBroadcast( LPCGUID lpcGuid, + DWORD dwFlags, + LPSPINITDATA lpSpData ); + BOOL NS_InitializeSessionCache( LPVOID* lplpNSInfo ); void NS_DeleteSessionCache( LPVOID lpNSInfo ); +void NS_InvalidateSessionCache( LPVOID lpNSInfo ); + void NS_ResetSessionEnumeration( LPVOID lpNSInfo ); LPDPSESSIONDESC2 NS_WalkSessions( LPVOID lpNSInfo ); +void NS_PruneSessionCache( LPVOID lpNSInfo ); #endif /* __WINE_DPLAYX_NAMESERVER */ diff --git a/include/dplay.h b/include/dplay.h index 891a9f3ee92..966c0e117bd 100644 --- a/include/dplay.h +++ b/include/dplay.h @@ -13,6 +13,13 @@ extern "C" { #include "pshpack1.h" +typedef LPVOID (*LPRGLPVOID)[]; +typedef LPRGLPVOID PRGPVOID, LPRGPVOID, PRGLPVOID, PAPVOID, LPAPVOID, PALPVOID, LPALPVOID; + +#define VOL volatile +typedef VOID *VOL LPVOIDV; + + /***************************************************************************** * Predeclare the interfaces */ @@ -283,6 +290,13 @@ typedef struct tagDPCHAT }msgstr; } DPCHAT, *LPDPCHAT; +typedef struct +{ + UINT len; + PUCHAR pData; +} SGBUFFER, *PSGBUFFER, *LPSGBUFFER; + + typedef struct tagDPSECURITYDESC { DWORD dwSize; /* Size of structure */ @@ -342,14 +356,7 @@ typedef BOOL CALLBACK (*LPDPENUMDPCALLBACKA)( DWORD dwMinorVersion, /* Minor # of driver spec in lpguidSP */ LPVOID lpContext); /* User given */ -/* NOTE: This isn't in the dplay.h header file, but this shouldn't be - * a problem. We require this because we include all these header files - * which declare GUIDs in guid.c - */ -#ifndef __LPCGUID_DEFINED__ -#define __LPCGUID_DEFINED__ typedef const GUID *LPCGUID; -#endif typedef const DPNAME *LPCDPNAME; diff --git a/ole/Makefile.in b/ole/Makefile.in index 774603023a5..17c48388a90 100644 --- a/ole/Makefile.in +++ b/ole/Makefile.in @@ -6,7 +6,6 @@ VPATH = @srcdir@ MODULE = ole C_SRCS = \ - guid.c \ ole2nls.c EXTRASUBDIRS = nls diff --git a/ole/guid.c b/ole/guid.c deleted file mode 100644 index 2a210e62f7f..00000000000 --- a/ole/guid.c +++ /dev/null @@ -1,32 +0,0 @@ -#define INITGUID - -/* FIXME: we include all the header files containing GUIDs - * so that the corresponding variables get defined. But they - * don't even all belong to the same DLL !!! - * - * Therefore, as the builtin DLL's get teased apart (e.g. for elf-dlls) - * then this file will have to be partitioned into per dll files. - */ -#include "initguid.h" - -#if 0 -#include "shlguid.h" -#include "docobj.h" -#include "olectl.h" -#include "oleidl.h" -#include "oaidl.h" -#include "ocidl.h" -#include "objbase.h" -#include "servprov.h" -#include "ddraw.h" -#include "d3d.h" -#include "dinput.h" -#include "dsound.h" -#include "dplay.h" -#include "dplobby.h" -#include "vfw.h" -#include "shlobj.h" -#endif - -/* and now for the one assumed GUID... */ -DEFINE_GUID(GUID_NULL, 0,0,0,0,0,0,0,0,0,0,0);