From 5bd48cf0fac7d35805fd4423b47fb814e5b7e2c8 Mon Sep 17 00:00:00 2001 From: Magnus Olsen Date: Thu, 27 Oct 2005 22:10:33 +0000 Subject: [PATCH] Addin wine 0.9 dplay and dplayx it is directx core for network and tested in windows and not in reactos. it is working in windows. svn path=/trunk/; revision=18811 --- reactos/lib/directory.xml | 6 + reactos/lib/dplay/dplay.spec | 4 + reactos/lib/dplay/dplay.xml | 25 + reactos/lib/dplay/dplay_main.c | 1 + reactos/lib/dplay/version.rc | 27 + reactos/lib/dplayx/dpclassfactory.c | 134 + reactos/lib/dplayx/dpinit.h | 37 + reactos/lib/dplayx/dplay.c | 5451 ++++++++++++++++++++++++++ reactos/lib/dplayx/dplay_global.h | 246 ++ reactos/lib/dplayx/dplaysp.c | 955 +++++ reactos/lib/dplayx/dplaysp.h | 366 ++ reactos/lib/dplayx/dplayx.spec | 12 + reactos/lib/dplayx/dplayx.xml | 33 + reactos/lib/dplayx/dplayx_global.c | 1354 +++++++ reactos/lib/dplayx/dplayx_global.h | 76 + reactos/lib/dplayx/dplayx_main.c | 111 + reactos/lib/dplayx/dplayx_messages.c | 511 +++ reactos/lib/dplayx/dplayx_messages.h | 223 ++ reactos/lib/dplayx/dplayx_queue.h | 216 + reactos/lib/dplayx/dplobby.c | 2012 ++++++++++ reactos/lib/dplayx/lobbysp.c | 462 +++ reactos/lib/dplayx/lobbysp.h | 520 +++ reactos/lib/dplayx/name_server.c | 425 ++ reactos/lib/dplayx/name_server.h | 61 + reactos/lib/dplayx/regsvr.c | 556 +++ reactos/lib/dplayx/version.rc | 27 + 26 files changed, 13851 insertions(+) create mode 100644 reactos/lib/dplay/dplay.spec create mode 100644 reactos/lib/dplay/dplay.xml create mode 100644 reactos/lib/dplay/dplay_main.c create mode 100644 reactos/lib/dplay/version.rc create mode 100644 reactos/lib/dplayx/dpclassfactory.c create mode 100644 reactos/lib/dplayx/dpinit.h create mode 100644 reactos/lib/dplayx/dplay.c create mode 100644 reactos/lib/dplayx/dplay_global.h create mode 100644 reactos/lib/dplayx/dplaysp.c create mode 100644 reactos/lib/dplayx/dplaysp.h create mode 100644 reactos/lib/dplayx/dplayx.spec create mode 100644 reactos/lib/dplayx/dplayx.xml create mode 100644 reactos/lib/dplayx/dplayx_global.c create mode 100644 reactos/lib/dplayx/dplayx_global.h create mode 100644 reactos/lib/dplayx/dplayx_main.c create mode 100644 reactos/lib/dplayx/dplayx_messages.c create mode 100644 reactos/lib/dplayx/dplayx_messages.h create mode 100644 reactos/lib/dplayx/dplayx_queue.h create mode 100644 reactos/lib/dplayx/dplobby.c create mode 100644 reactos/lib/dplayx/lobbysp.c create mode 100644 reactos/lib/dplayx/lobbysp.h create mode 100644 reactos/lib/dplayx/name_server.c create mode 100644 reactos/lib/dplayx/name_server.h create mode 100644 reactos/lib/dplayx/regsvr.c create mode 100644 reactos/lib/dplayx/version.rc diff --git a/reactos/lib/directory.xml b/reactos/lib/directory.xml index c707804511e..79137adc825 100644 --- a/reactos/lib/directory.xml +++ b/reactos/lib/directory.xml @@ -62,6 +62,12 @@ + + + + + + diff --git a/reactos/lib/dplay/dplay.spec b/reactos/lib/dplay/dplay.spec new file mode 100644 index 00000000000..9ee08c1fe40 --- /dev/null +++ b/reactos/lib/dplay/dplay.spec @@ -0,0 +1,4 @@ +# First DirectPlay dll. Replaced by dplayx.dll. + +@ stdcall DirectPlayCreate(ptr ptr ptr) dplayx.DirectPlayCreate +@ stdcall DirectPlayEnumerate(ptr ptr) dplayx.DirectPlayEnumerate diff --git a/reactos/lib/dplay/dplay.xml b/reactos/lib/dplay/dplay.xml new file mode 100644 index 00000000000..2409c1e27d3 --- /dev/null +++ b/reactos/lib/dplay/dplay.xml @@ -0,0 +1,25 @@ + + + . + include/wine + + + + + 0x600 + 0x501 + 0x501 + wine + uuid + ntdll + kernel32 + user32 + advapi32 + ole32 + winmm + dxguid + dinput + version.rc + dplay_main.c + dplay.spec + diff --git a/reactos/lib/dplay/dplay_main.c b/reactos/lib/dplay/dplay_main.c new file mode 100644 index 00000000000..67a01ed518c --- /dev/null +++ b/reactos/lib/dplay/dplay_main.c @@ -0,0 +1 @@ +/* nothing here yet */ diff --git a/reactos/lib/dplay/version.rc b/reactos/lib/dplay/version.rc new file mode 100644 index 00000000000..731bef2570c --- /dev/null +++ b/reactos/lib/dplay/version.rc @@ -0,0 +1,27 @@ +/* + * Copyright 2004 Tom Wickline + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define WINE_OLESELFREGISTER +#define WINE_FILEDESCRIPTION_STR "Wine DirectPlay" +#define WINE_FILENAME_STR "dplay.dll" +#define WINE_FILEVERSION 5,3,0,900 +#define WINE_FILEVERSION_STR "5.3.0.900" +#define WINE_PRODUCTVERSION 5,3,0,900 +#define WINE_PRODUCTVERSION_STR "5.3" + +#include "wine/wine_common_ver.rc" diff --git a/reactos/lib/dplayx/dpclassfactory.c b/reactos/lib/dplayx/dpclassfactory.c new file mode 100644 index 00000000000..610b44bdd56 --- /dev/null +++ b/reactos/lib/dplayx/dpclassfactory.c @@ -0,0 +1,134 @@ +/* COM class factory for direct play lobby interfaces. + * + * Copyright 1999, 2000 Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "dpinit.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + + +/******************************************************************************* + * DirectPlayLobby ClassFactory + */ + +typedef struct +{ + /* IUnknown fields */ + const IClassFactoryVtbl *lpVtbl; + LONG ref; +} IClassFactoryImpl; + +static HRESULT WINAPI +DP_and_DPL_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); + + return E_NOINTERFACE; +} + +static ULONG WINAPI +DP_and_DPL_AddRef(LPCLASSFACTORY iface) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI DP_and_DPL_Release(LPCLASSFACTORY iface) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + /* static class (reference starts @ 1), won't ever be freed */ + return InterlockedDecrement(&This->ref); +} + +static HRESULT WINAPI DP_and_DPL_CreateInstance( + LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj +) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); + + if ( DPL_CreateInterface( riid, ppobj ) == S_OK ) + { + return S_OK; + } + else if ( DP_CreateInterface( riid, ppobj ) == S_OK ) + { + return S_OK; + } + + return E_NOINTERFACE; +} + +static HRESULT WINAPI DP_and_DPL_LockServer(LPCLASSFACTORY iface,BOOL dolock) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + FIXME("(%p)->(%d),stub!\n",This,dolock); + return S_OK; +} + +static const IClassFactoryVtbl DP_and_DPL_Vtbl = { + DP_and_DPL_QueryInterface, + DP_and_DPL_AddRef, + DP_and_DPL_Release, + DP_and_DPL_CreateInstance, + DP_and_DPL_LockServer +}; + +static IClassFactoryImpl DP_and_DPL_CF = {&DP_and_DPL_Vtbl, 1 }; + + +/******************************************************************************* + * DllGetClassObject [DPLAYX.@] + * Retrieves DP or DPL class object from a DLL object + * + * NOTES + * Docs say returns STDAPI + * + * PARAMS + * rclsid [I] CLSID for the class object + * riid [I] Reference to identifier of interface for class object + * ppv [O] Address of variable to receive interface pointer for riid + * + * RETURNS + * Success: S_OK + * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG, + * E_UNEXPECTED + */ +HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + + if ( IsEqualCLSID( riid, &IID_IClassFactory ) ) + { + *ppv = (LPVOID)&DP_and_DPL_CF; + IClassFactory_AddRef( (IClassFactory*)*ppv ); + + return S_OK; + } + + ERR("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/reactos/lib/dplayx/dpinit.h b/reactos/lib/dplayx/dpinit.h new file mode 100644 index 00000000000..df728777ceb --- /dev/null +++ b/reactos/lib/dplayx/dpinit.h @@ -0,0 +1,37 @@ +/* + * Copyright 1999, 2000 Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_DPINIT_H +#define __WINE_DPINIT_H + +#include + +#include "windef.h" +#include "winbase.h" +#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 ); +extern HRESULT DPLSP_CreateInterface( REFIID riid, LPVOID* ppvObj, + IDirectPlay2Impl* dp ); + + +#endif diff --git a/reactos/lib/dplayx/dplay.c b/reactos/lib/dplayx/dplay.c new file mode 100644 index 00000000000..020f72928b9 --- /dev/null +++ b/reactos/lib/dplayx/dplay.c @@ -0,0 +1,5451 @@ +/* Direct Play 2,3,4 Implementation + * + * Copyright 1998,1999,2000,2001 - Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winerror.h" +#include "winbase.h" +#include "winnt.h" +#include "winreg.h" +#include "winnls.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +#include "dpinit.h" +#include "dplayx_global.h" +#include "name_server.h" +#include "dplayx_queue.h" +#include "dplaysp.h" +#include "dplay_global.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +/* FIXME: Should this be externed? */ +extern HRESULT DPL_CreateCompoundAddress +( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount, + LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface ); + + +/* Local function prototypes */ +static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid ); +static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid, + LPDPNAME lpName, DWORD dwFlags, + HANDLE hEvent, BOOL bAnsi ); +static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi ); +static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize ); + +static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, LPDPID lpid, + 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 CALLBACK cbDeletePlayerFromAllGroups( DPID dpId, + DWORD dwPlayerType, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext ); +static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid ); +static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType, + LPCDPNAME lpName, DWORD dwFlags, + LPVOID lpContext ); +static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid ); + +/* Forward declarations of virtual tables */ +static const IDirectPlay2Vtbl directPlay2AVT; +static const IDirectPlay3Vtbl directPlay3AVT; +static const IDirectPlay4Vtbl directPlay4AVT; + +static const IDirectPlay2Vtbl directPlay2WVT; +static const IDirectPlay3Vtbl directPlay3WVT; +static const IDirectPlay4Vtbl directPlay4WVT; + +/* Helper methods for player/group interfaces */ +static HRESULT WINAPI DP_IF_DeletePlayerFromGroup + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, + DPID idPlayer, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_CreatePlayer + ( 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, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_DestroyPlayer + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_EnumGroupPlayers + ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_EnumGroups + ( IDirectPlay2Impl* This, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_EnumPlayers + ( IDirectPlay2Impl* This, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_GetGroupData + ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, + LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_GetGroupName + ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, + LPDWORD lpdwDataSize, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_GetPlayerData + ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, + LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_GetPlayerName + ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, + LPDWORD lpdwDataSize, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_SetGroupName + ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName, + DWORD dwFlags, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_SetPlayerData + ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, + DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_SetPlayerName + ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName, + 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, 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, + 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 HRESULT WINAPI DP_IF_GetCaps + ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags ); +static HRESULT WINAPI DP_IF_EnumSessions + ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, + LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, + LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ); +static HRESULT WINAPI DP_IF_InitializeConnection + ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi ); +static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP, + LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName, + DWORD dwFlags, LPVOID lpContext ); +static BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf, + LPDWORD lpdwBufSize ); + + + +static inline DPID DP_NextObjectId(void); +static DPID DP_GetRemoteNextObjectId(void); + + +static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc, + LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi ); + + +static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp ); +static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider ); +static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider ); + + + + + + +#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 LONG kludgePlayerGroupId = 1000; + +/* ------------------------------------------------------------------ */ + + +static BOOL DP_CreateIUnknown( LPVOID lpDP ) +{ + IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP; + + This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) ); + if ( This->unk == NULL ) + { + return FALSE; + } + + InitializeCriticalSection( &This->unk->DP_lock ); + + return TRUE; +} + +static BOOL DP_DestroyIUnknown( LPVOID lpDP ) +{ + IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP; + + DeleteCriticalSection( &This->unk->DP_lock ); + HeapFree( GetProcessHeap(), 0, This->unk ); + + return TRUE; +} + +static BOOL DP_CreateDirectPlay2( LPVOID lpDP ) +{ + IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP; + + This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) ); + if ( This->dp2 == NULL ) + { + return FALSE; + } + + This->dp2->bConnectionOpen = FALSE; + + This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE; + + This->dp2->bHostInterface = FALSE; + + DPQ_INIT(This->dp2->receiveMsgs); + DPQ_INIT(This->dp2->sendMsgs); + DPQ_INIT(This->dp2->replysExpected); + + if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) ) + { + /* FIXME: Memory leak */ + return FALSE; + } + + /* Provide an initial session desc with nothing in it */ + This->dp2->lpSessionDesc = 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 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; + } + + /* Setup lobby provider information */ + This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION; + This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *This->dp2->dplspData.lpCB ) ); + This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB ); + + if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP, + (LPVOID*)&This->dp2->dplspData.lpISP, This ) ) + ) + { + /* FIXME: Memory leak */ + return FALSE; + } + + return TRUE; +} + +/* 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 ) +{ + IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP; + + if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE ) + { + TerminateThread( This->dp2->hEnumSessionThread, 0 ); + CloseHandle( This->dp2->hEnumSessionThread ); + } + + /* Finish with the SP - have it shutdown */ + if( This->dp2->spData.lpCB->ShutdownEx ) + { + DPSP_SHUTDOWNDATA data; + + TRACE( "Calling SP ShutdownEx\n" ); + + data.lpISP = This->dp2->spData.lpISP; + + (*This->dp2->spData.lpCB->ShutdownEx)( &data ); + } + else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */ + { + TRACE( "Calling obsolete SP Shutdown\n" ); + (*This->dp2->spData.lpCB->Shutdown)(); + } + + /* Unload the SP (if it exists) */ + if( This->dp2->hServiceProvider != 0 ) + { + FreeLibrary( This->dp2->hServiceProvider ); + } + + /* Unload the Lobby Provider (if it exists) */ + if( This->dp2->hDPLobbyProvider != 0 ) + { + FreeLibrary( This->dp2->hDPLobbyProvider ); + } + +#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; +} + +static BOOL DP_CreateDirectPlay3( LPVOID lpDP ) +{ + IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP; + + This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) ); + if ( This->dp3 == NULL ) + { + return FALSE; + } + + return TRUE; +} + +static BOOL DP_DestroyDirectPlay3( LPVOID lpDP ) +{ + IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP; + + /* Delete the contents */ + HeapFree( GetProcessHeap(), 0, This->dp3 ); + + return TRUE; +} + +static BOOL DP_CreateDirectPlay4( LPVOID lpDP ) +{ + IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)lpDP; + + This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) ); + if ( This->dp4 == NULL ) + { + return FALSE; + } + + return TRUE; +} + +static BOOL DP_DestroyDirectPlay4( LPVOID lpDP ) +{ + IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP; + + /* Delete the contents */ + HeapFree( GetProcessHeap(), 0, This->dp4 ); + + return TRUE; +} + + +/* Create a new interface */ +extern +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 ) ) + { + IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj; + This->lpVtbl = &directPlay2WVT; + } + else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) ) + { + IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj; + This->lpVtbl = &directPlay2AVT; + } + else if( IsEqualGUID( &IID_IDirectPlay3, riid ) ) + { + IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj; + This->lpVtbl = &directPlay3WVT; + } + else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) ) + { + IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj; + This->lpVtbl = &directPlay3AVT; + } + else if( IsEqualGUID( &IID_IDirectPlay4, riid ) ) + { + IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj; + This->lpVtbl = &directPlay4WVT; + } + else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) ) + { + IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj; + This->lpVtbl = &directPlay4AVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + return E_NOINTERFACE; + } + + /* 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 DPERR_NOMEMORY; +} + + +/* Direct Play methods */ + +/* Shared between all dplay types */ +static HRESULT WINAPI DP_QueryInterface + ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj ); + + *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *This ) ); + + if( *ppvObj == NULL ) + { + return DPERR_OUTOFMEMORY; + } + + CopyMemory( *ppvObj, This, sizeof( *This ) ); + (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0; + + if( IsEqualGUID( &IID_IDirectPlay2, riid ) ) + { + IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj; + This->lpVtbl = &directPlay2WVT; + } + else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) ) + { + IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj; + This->lpVtbl = &directPlay2AVT; + } + else if( IsEqualGUID( &IID_IDirectPlay3, riid ) ) + { + IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj; + This->lpVtbl = &directPlay3WVT; + } + else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) ) + { + IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj; + This->lpVtbl = &directPlay3AVT; + } + else if( IsEqualGUID( &IID_IDirectPlay4, riid ) ) + { + IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj; + This->lpVtbl = &directPlay4WVT; + } + else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) ) + { + IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj; + This->lpVtbl = &directPlay4AVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + return E_NOINTERFACE; + } + + IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj ); + + return S_OK; +} + +/* Shared between all dplay types */ +static ULONG WINAPI DP_AddRef + ( LPDIRECTPLAY3 iface ) +{ + ULONG ulInterfaceRefCount, ulObjRefCount; + IDirectPlay3Impl *This = (IDirectPlay3Impl *)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 DP_Release +( LPDIRECTPLAY3 iface ) +{ + ULONG ulInterfaceRefCount, ulObjRefCount; + + IDirectPlay3Impl *This = (IDirectPlay3Impl *)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 ) + { + /* 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 ); + } + + /* Deallocate the interface */ + if( ulInterfaceRefCount == 0 ) + { + HeapFree( GetProcessHeap(), 0, This ); + } + + return ulObjRefCount; +} + +static inline DPID DP_NextObjectId(void) +{ + return (DPID)InterlockedIncrement( &kludgePlayerGroupId ); +} + +/* *lplpReply will be non NULL iff there is something to reply */ +HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody, + DWORD dwMessageBodySize, LPCVOID lpcMessageHeader, + WORD wCommandId, WORD wVersion, + LPVOID* lplpReply, LPDWORD lpdwMsgSize ) +{ + TRACE( "(%p)->(%p,0x%08lx,%p,%u,%u)\n", + This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId, + wVersion ); + + switch( wCommandId ) + { + /* Name server needs to handle this request */ + case DPMSGCMD_ENUMSESSIONSREQUEST: + { + /* Reply expected */ + NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This ); + + break; + } + + /* Name server needs to handle this request */ + case DPMSGCMD_ENUMSESSIONSREPLY: + { + /* No reply expected */ + NS_AddRemoteComputerAsNameServer( lpcMessageHeader, + This->dp2->spData.dwSPHeaderSize, + (LPDPMSG_ENUMSESSIONSREPLY)lpcMessageBody, + This->dp2->lpNameServerData ); + break; + } + + case DPMSGCMD_REQUESTNEWPLAYERID: + { + LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = + (LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody; + + LPDPMSG_NEWPLAYERIDREPLY lpReply; + + *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply ); + + *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize ); + + FIXME( "Ignoring dwFlags 0x%08lx in request msg\n", + lpcMsg->dwFlags ); + + /* Setup the reply */ + lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) + + This->dp2->spData.dwSPHeaderSize ); + + lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG; + lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY; + lpReply->envelope.wVersion = DPMSGVER_DP6; + + lpReply->dpidNewPlayerId = DP_NextObjectId(); + + TRACE( "Allocating new playerid 0x%08lx from remote request\n", + lpReply->dpidNewPlayerId ); + + break; + } + + case DPMSGCMD_GETNAMETABLEREPLY: + case DPMSGCMD_NEWPLAYERIDREPLY: + { + +#if 0 + if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY ) + DebugBreak(); +#endif + DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize ); + + break; + } + +#if 1 + case DPMSGCMD_JUSTENVELOPE: + { + TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08lx\n", lpcMessageHeader, ((LPDWORD)lpcMessageHeader)[1] ); + NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 ); + DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize ); + } +#endif + + case DPMSGCMD_FORWARDADDPLAYER: + { +#if 0 + DebugBreak(); +#endif +#if 1 + TRACE( "Sending message to self to get my addr\n" ); + DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */ +#endif + break; + } + + case DPMSGCMD_FORWARDADDPLAYERNACK: + { + DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize ); + break; + } + + default: + { + FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId ); + DebugBreak(); + break; + } + } + + /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */ + + return DP_OK; +} + + +static HRESULT WINAPI DP_IF_AddPlayerToGroup + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, + DPID idPlayer, BOOL bAnsi ) +{ + lpGroupData lpGData; + lpPlayerList lpPList; + lpPlayerList lpNewPList; + + TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n", + This, lpMsgHdr, idGroup, idPlayer, bAnsi ); + + /* Find the group */ + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + /* Find the player */ + if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL ) + { + return DPERR_INVALIDPLAYER; + } + + /* Create a player list (ie "shortcut" ) */ + lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) ); + if( lpNewPList == NULL ) + { + return DPERR_CANTADDPLAYER; + } + + /* Add the shortcut */ + lpPList->lpPData->uRef++; + lpNewPList->lpPData = lpPList->lpPData; + + /* Add the player to the list of players for this group */ + DPQ_INSERT(lpGData->players,lpNewPList,players); + + /* 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 ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup + ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE ); +} + +static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi ) +{ + HRESULT hr = DP_OK; + + TRACE("(%p)->(%u)\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)(); + } + + return hr; +} + +static HRESULT WINAPI DirectPlay2AImpl_Close + ( LPDIRECTPLAY2A iface ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_Close( This, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_Close + ( LPDIRECTPLAY2 iface ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_Close( This, FALSE ); +} + +static +lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, LPDPID lpid, + LPDPNAME lpName, DWORD dwFlags, + DPID idParent, BOOL bAnsi ) +{ + lpGroupData lpGData; + + /* Allocate the new space and add to end of high level group list */ + lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) ); + + if( lpGData == NULL ) + { + return NULL; + } + + DPQ_INIT(lpGData->groups); + DPQ_INIT(lpGData->players); + + /* Set the desired player ID - no sanity checking to see if it exists */ + lpGData->dpid = *lpid; + + DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi ); + + /* FIXME: Should we check that the parent exists? */ + lpGData->parent = idParent; + + /* FIXME: Should we validate the dwFlags? */ + lpGData->dwFlags = dwFlags; + + TRACE( "Created group id 0x%08lx\n", *lpid ); + + return lpGData; +} + +/* This method assumes that all links to it are already deleted */ +static void +DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid ) +{ + lpGroupList lpGList; + + TRACE( "(%p)->(0x%08lx)\n", This, dpid ); + + DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList ); + + if( lpGList == NULL ) + { + ERR( "DPID 0x%08lx not found\n", dpid ); + return; + } + + if( --(lpGList->lpGData->uRef) ) + { + FIXME( "Why is this not the last reference to group?\n" ); + DebugBreak(); + } + + /* Delete player */ + DP_DeleteDPNameStruct( &lpGList->lpGData->name ); + HeapFree( GetProcessHeap(), 0, lpGList->lpGData ); + + /* Remove and Delete Player List object */ + HeapFree( GetProcessHeap(), 0, lpGList ); + +} + +static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid ) +{ + lpGroupList lpGroups; + + TRACE( "(%p)->(0x%08lx)\n", This, dpid ); + + if( dpid == DPID_SYSTEM_GROUP ) + { + return This->dp2->lpSysGroup; + } + else + { + DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups ); + } + + if( lpGroups == NULL ) + { + return NULL; + } + + return lpGroups->lpGData; +} + +static HRESULT WINAPI DP_IF_CreateGroup + ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup, + LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, + DWORD dwFlags, BOOL bAnsi ) +{ + lpGroupData lpGData; + + TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n", + This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize, + dwFlags, bAnsi ); + + /* 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 + { + *lpidGroup = DP_GetRemoteNextObjectId(); + } + } + + lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags, + DPID_NOPARENT_GROUP, bAnsi ); + + if( lpGData == NULL ) + { + return DPERR_CANTADDPLAYER; /* yes player not group */ + } + + if( DPID_SYSTEM_GROUP == *lpidGroup ) + { + This->dp2->lpSysGroup = lpGData; + TRACE( "Inserting system group\n" ); + } + else + { + /* Insert into the system group */ + lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) ); + lpGroup->lpGData = lpGData; + + DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups ); + } + + /* Something is now referencing this data */ + lpGData->uRef++; + + /* 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, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize ) +{ + /* Clear out the data with this player */ + if( dwFlags & DPSET_LOCAL ) + { + if ( lpGData->dwLocalDataSize != 0 ) + { + HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData ); + lpGData->lpLocalData = NULL; + lpGData->dwLocalDataSize = 0; + } + } + else + { + if( lpGData->dwRemoteDataSize != 0 ) + { + HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData ); + lpGData->lpRemoteData = NULL; + lpGData->dwRemoteDataSize = 0; + } + } + + /* Reallocate for new data */ + if( lpData != NULL ) + { + LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( dwDataSize ) ); + CopyMemory( lpNewData, lpData, dwDataSize ); + + if( dwFlags & DPSET_LOCAL ) + { + lpGData->lpLocalData = lpData; + lpGData->dwLocalDataSize = dwDataSize; + } + else + { + lpGData->lpRemoteData = lpNewData; + lpGData->dwRemoteDataSize = dwDataSize; + } + } + +} + +/* This function will just create the storage for the new player. */ +static +lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid, + LPDPNAME lpName, DWORD dwFlags, + HANDLE hEvent, BOOL bAnsi ) +{ + lpPlayerData lpPData; + + TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi ); + + /* Allocate the storage for the player and associate it with list element */ + lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) ); + if( lpPData == NULL ) + { + return NULL; + } + + /* Set the desired player ID */ + lpPData->dpid = *lpid; + + DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi ); + + lpPData->dwFlags = dwFlags; + + /* If we were given an event handle, duplicate it */ + if( hEvent != 0 ) + { + if( !DuplicateHandle( GetCurrentProcess(), hEvent, + GetCurrentProcess(), &lpPData->hEvent, + 0, FALSE, DUPLICATE_SAME_ACCESS ) + ) + { + /* FIXME: Memory leak */ + ERR( "Can't duplicate player msg handle %p\n", hEvent ); + } + } + + /* Initialize the SP data section */ + lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData(); + + TRACE( "Created player id 0x%08lx\n", *lpid ); + + return lpPData; +} + +/* Delete the contents of the DPNAME struct */ +static void +DP_DeleteDPNameStruct( LPDPNAME lpDPName ) +{ + HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->lpszShortNameA ); + HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->lpszLongNameA ); +} + +/* This method assumes that all links to it are already deleted */ +static void +DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid ) +{ + lpPlayerList lpPList; + + TRACE( "(%p)->(0x%08lx)\n", This, dpid ); + + DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList ); + + if( lpPList == NULL ) + { + ERR( "DPID 0x%08lx not found\n", dpid ); + return; + } + + /* Verify that this is the last reference to the data */ + if( --(lpPList->lpPData->uRef) ) + { + FIXME( "Why is this not the last reference to player?\n" ); + DebugBreak(); + } + + /* Delete player */ + DP_DeleteDPNameStruct( &lpPList->lpPData->name ); + + CloseHandle( lpPList->lpPData->hEvent ); + HeapFree( GetProcessHeap(), 0, lpPList->lpPData ); + + /* Delete Player List object */ + HeapFree( GetProcessHeap(), 0, lpPList ); +} + +static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid ) +{ + lpPlayerList lpPlayers; + + TRACE( "(%p)->(0x%08lx)\n", This, dpid ); + + DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers ); + + return lpPlayers; +} + +/* Basic area for Dst must already be allocated */ +static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi ) +{ + if( lpSrc == NULL ) + { + ZeroMemory( lpDst, sizeof( *lpDst ) ); + lpDst->dwSize = sizeof( *lpDst ); + return TRUE; + } + + if( lpSrc->dwSize != sizeof( *lpSrc) ) + { + return FALSE; + } + + /* Delete any existing pointers */ + HeapFree( GetProcessHeap(), 0, lpDst->lpszShortNameA ); + HeapFree( GetProcessHeap(), 0, lpDst->lpszLongNameA ); + + /* Copy as required */ + CopyMemory( lpDst, lpSrc, lpSrc->dwSize ); + + if( bAnsi ) + { + if( lpSrc->lpszShortNameA ) + { + lpDst->lpszShortNameA = HeapAlloc( GetProcessHeap(), 0, + strlen(lpSrc->lpszShortNameA)+1 ); + strcpy( lpDst->lpszShortNameA, lpSrc->lpszShortNameA ); + } + if( lpSrc->lpszLongNameA ) + { + lpDst->lpszLongNameA = HeapAlloc( GetProcessHeap(), 0, + strlen(lpSrc->lpszLongNameA)+1 ); + strcpy( lpDst->lpszLongNameA, lpSrc->lpszLongNameA ); + } + } + else + { + if( lpSrc->lpszShortNameA ) + { + lpDst->lpszShortName = HeapAlloc( GetProcessHeap(), 0, + (strlenW(lpSrc->lpszShortName)+1)*sizeof(WCHAR) ); + strcpyW( lpDst->lpszShortName, lpSrc->lpszShortName ); + } + if( lpSrc->lpszLongNameA ) + { + lpDst->lpszLongName = HeapAlloc( GetProcessHeap(), 0, + (strlenW(lpSrc->lpszLongName)+1)*sizeof(WCHAR) ); + strcpyW( lpDst->lpszLongName, lpSrc->lpszLongName ); + } + } + + return TRUE; +} + +static void +DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags, + LPVOID lpData, DWORD dwDataSize ) +{ + /* Clear out the data with this player */ + if( dwFlags & DPSET_LOCAL ) + { + if ( lpPData->dwLocalDataSize != 0 ) + { + HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData ); + lpPData->lpLocalData = NULL; + lpPData->dwLocalDataSize = 0; + } + } + else + { + if( lpPData->dwRemoteDataSize != 0 ) + { + HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData ); + lpPData->lpRemoteData = NULL; + lpPData->dwRemoteDataSize = 0; + } + } + + /* Reallocate for new data */ + if( lpData != NULL ) + { + LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( dwDataSize ) ); + CopyMemory( lpNewData, lpData, dwDataSize ); + + if( dwFlags & DPSET_LOCAL ) + { + lpPData->lpLocalData = lpData; + lpPData->dwLocalDataSize = dwDataSize; + } + else + { + lpPData->lpRemoteData = lpNewData; + lpPData->dwRemoteDataSize = 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, + LPVOID lpData, + DWORD dwDataSize, + DWORD dwFlags, + BOOL bAnsi ) +{ + HRESULT hr = DP_OK; + lpPlayerData lpPData; + lpPlayerList lpPList; + DWORD dwCreateFlags = 0; + + TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n", + This, lpidPlayer, lpPlayerName, hEvent, lpData, + dwDataSize, dwFlags, bAnsi ); + + if( dwFlags == 0 ) + { + dwFlags = DPPLAYER_SPECTATOR; + } + + if( lpidPlayer == NULL ) + { + return DPERR_INVALIDPARAMS; + } + + + /* Determine the creation flags for the player. These will be passed + * to the name server if requesting a player id and to the SP when + * informing it of the player creation + */ + { + if( dwFlags & DPPLAYER_SERVERPLAYER ) + { + if( *lpidPlayer == DPID_SERVERPLAYER ) + { + /* Server player for the host interface */ + dwCreateFlags |= DPLAYI_PLAYER_APPSERVER; + } + else if( *lpidPlayer == DPID_NAME_SERVER ) + { + /* Name server - master of everything */ + dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER); + } + else + { + /* Server player for a non host interface */ + dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER; + } + } + + if( lpMsgHdr == NULL ) + dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL; + } + + /* Verify we know how to handle all the flags */ + if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) || + ( dwFlags & DPPLAYER_SPECTATOR ) + ) + ) + { + /* Assume non fatal failure */ + ERR( "unknown dwFlags = 0x%08lx\n", dwFlags ); + } + + /* If the name is not specified, we must provide one */ + if( *lpidPlayer == DPID_UNKNOWN ) + { + /* If we are the session master, we dish out the group/player ids */ + if( This->dp2->bHostInterface ) + { + *lpidPlayer = DP_NextObjectId(); + } + else + { + hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer ); + + if( FAILED(hr) ) + { + ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) ); + return hr; + } + } + } + else + { + /* FIXME: Would be nice to perhaps verify that we don't already have + * this player. + */ + } + + /* FIXME: Should we be storing these dwFlags or the creation ones? */ + lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags, + hEvent, bAnsi ); + + if( lpPData == NULL ) + { + return DPERR_CANTADDPLAYER; + } + + /* Create the list object and link it in */ + lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) ); + if( lpPList == NULL ) + { + FIXME( "Memory leak\n" ); + return DPERR_CANTADDPLAYER; + } + + lpPData->uRef = 1; + lpPList->lpPData = lpPData; + + /* Add the player to the system group */ + DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players ); + + /* Update the information and send it to all players in the session */ + DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize ); + + /* Let the SP know that we've created this player */ + if( This->dp2->spData.lpCB->CreatePlayer ) + { + DPSP_CREATEPLAYERDATA data; + + data.idPlayer = *lpidPlayer; + data.dwFlags = dwCreateFlags; + data.lpSPMessageHeader = lpMsgHdr; + data.lpISP = This->dp2->spData.lpISP; + + TRACE( "Calling SP CreatePlayer 0x%08lx: dwFlags: 0x%08lx lpMsgHdr: %p\n", + *lpidPlayer, data.dwFlags, data.lpSPMessageHeader ); + + hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data ); + } + + if( FAILED(hr) ) + { + ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) ); + return hr; + } + + /* Now let the SP know that this player is a member of the system group */ + if( This->dp2->spData.lpCB->AddPlayerToGroup ) + { + DPSP_ADDPLAYERTOGROUPDATA data; + + data.idPlayer = *lpidPlayer; + data.idGroup = DPID_SYSTEM_GROUP; + data.lpISP = This->dp2->spData.lpISP; + + TRACE( "Calling SP AddPlayerToGroup (sys group)\n" ); + + hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data ); + } + + if( FAILED(hr) ) + { + ERR( "Failed to add player to sys group with sp: %s\n", + DPLAYX_HresultToString(hr) ); + return hr; + } + +#if 1 + if( This->dp2->bHostInterface == FALSE ) + { + /* Let the name server know about the creation of this player */ + /* FIXME: Is this only to be done for the creation of a server player or + * is this used for regular players? If only for server players, move + * this call to DP_SecureOpen(...); + */ +#if 0 + TRACE( "Sending message to self to get my addr\n" ); + DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */ +#endif + + hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer); + } +#else + /* 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 */ + hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, + sizeof( msg ), 0, 0, NULL, NULL, bAnsi ); + } +#endif + + return hr; +} + +static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer + ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, + HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + + if( dwFlags & DPPLAYER_SERVERPLAYER ) + { + *lpidPlayer = DPID_SERVERPLAYER; + } + else + { + *lpidPlayer = DPID_UNKNOWN; + } + + return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent, + lpData, dwDataSize, dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer + ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, + HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + + 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 DPID DP_GetRemoteNextObjectId(void) +{ + FIXME( ":stub\n" ); + + /* Hack solution */ + return DP_NextObjectId(); +} + +static HRESULT WINAPI DP_IF_DeletePlayerFromGroup + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, + DPID idPlayer, BOOL bAnsi ) +{ + HRESULT hr = DP_OK; + + lpGroupData lpGData; + lpPlayerList lpPList; + + TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n", + This, lpMsgHdr, idGroup, idPlayer, bAnsi ); + + /* Find the group */ + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + /* Find the player */ + if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL ) + { + return DPERR_INVALIDPLAYER; + } + + /* Remove the player shortcut from the group */ + DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList ); + + if( lpPList == NULL ) + { + return DPERR_INVALIDPLAYER; + } + + /* One less reference */ + lpPList->lpPData->uRef--; + + /* 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 hr; +} + +static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup + ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup + ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE ); +} + +typedef struct _DPRGOPContext +{ + IDirectPlay3Impl* This; + BOOL bAnsi; + DPID idGroup; +} DPRGOPContext, *lpDPRGOPContext; + +static BOOL CALLBACK +cbRemoveGroupOrPlayer( + DPID dpId, + DWORD dwPlayerType, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext ) +{ + lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext; + + TRACE( "Removing element:0x%08lx (type:0x%08lx) from element:0x%08lx\n", + dpId, dwPlayerType, lpCtxt->idGroup ); + + if( dwPlayerType == DPPLAYERTYPE_GROUP ) + { + if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup, + dpId ) + ) + ) + { + ERR( "Unable to delete group 0x%08lx from group 0x%08lx\n", + dpId, lpCtxt->idGroup ); + } + } + else + { + if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This, + NULL, lpCtxt->idGroup, + dpId, lpCtxt->bAnsi ) + ) + ) + { + ERR( "Unable to delete player 0x%08lx from grp 0x%08lx\n", + dpId, lpCtxt->idGroup ); + } + } + + return TRUE; /* Continue enumeration */ +} + +static HRESULT WINAPI DP_IF_DestroyGroup + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi ) +{ + lpGroupData lpGData; + DPRGOPContext context; + + FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n", + This, lpMsgHdr, idGroup, bAnsi ); + + /* Find the group */ + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + { + return DPERR_INVALIDPLAYER; /* yes player */ + } + + context.This = (IDirectPlay3Impl*)This; + context.bAnsi = bAnsi; + context.idGroup = idGroup; + + /* Remove all players that this group has */ + DP_IF_EnumGroupPlayers( This, idGroup, NULL, + cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi ); + + /* Remove all links to groups that this group has since this is dp3 */ + DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL, + cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi ); + + /* Remove this group from the parent group - if it has one */ + if( ( idGroup != DPID_SYSTEM_GROUP ) && + ( lpGData->parent != DPID_SYSTEM_GROUP ) + ) + { + DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent, + idGroup ); + } + + /* Now delete this group data and list from the system group */ + DP_DeleteGroup( This, idGroup ); + + /* 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; +} + +static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup + ( LPDIRECTPLAY2A iface, DPID idGroup ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup + ( LPDIRECTPLAY2 iface, DPID idGroup ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE ); +} + +typedef struct _DPFAGContext +{ + IDirectPlay2Impl* This; + DPID idPlayer; + BOOL bAnsi; +} DPFAGContext, *lpDPFAGContext; + +static HRESULT WINAPI DP_IF_DestroyPlayer + ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi ) +{ + DPFAGContext cbContext; + + FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n", + This, lpMsgHdr, idPlayer, bAnsi ); + + if( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + + if( DP_FindPlayer( This, idPlayer ) == NULL ) + { + return DPERR_INVALIDPLAYER; + } + + /* FIXME: If the player is remote, we must be the host to delete this */ + + cbContext.This = This; + cbContext.idPlayer = idPlayer; + cbContext.bAnsi = bAnsi; + + /* Find each group and call DeletePlayerFromGroup if the player is a + member of the group */ + DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups, + (LPVOID)&cbContext, DPENUMGROUPS_ALL, bAnsi ); + + /* Now delete player and player list from the sys group */ + DP_DeletePlayer( This, idPlayer ); + + /* 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; +} + +static BOOL CALLBACK +cbDeletePlayerFromAllGroups( + DPID dpId, + DWORD dwPlayerType, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext ) +{ + lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext; + + if( dwPlayerType == DPPLAYERTYPE_GROUP ) + { + DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer, + lpCtxt->bAnsi ); + + /* Enumerate all groups in this group since this will normally only + * be called for top level groups + */ + DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This, + dpId, NULL, + cbDeletePlayerFromAllGroups, + (LPVOID)lpContext, DPENUMGROUPS_ALL, + lpCtxt->bAnsi ); + + } + else + { + ERR( "Group callback has dwPlayerType = 0x%08lx\n", dwPlayerType ); + } + + return TRUE; +} + +static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer + ( LPDIRECTPLAY2A iface, DPID idPlayer ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer + ( LPDIRECTPLAY2 iface, DPID idPlayer ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE ); +} + +static HRESULT WINAPI DP_IF_EnumGroupPlayers + ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ) +{ + lpGroupData lpGData; + lpPlayerList lpPList; + + FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n", + This, idGroup, lpguidInstance, lpEnumPlayersCallback2, + lpContext, dwFlags, bAnsi ); + + if( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + + /* 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; +} + +static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers + ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance, + lpEnumPlayersCallback2, lpContext, + dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers + ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance, + lpEnumPlayersCallback2, lpContext, + dwFlags, FALSE ); +} + +/* NOTE: This only enumerates top level groups (created with CreateGroup) */ +static HRESULT WINAPI DP_IF_EnumGroups + ( IDirectPlay2Impl* This, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ) +{ + return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, + DPID_SYSTEM_GROUP, lpguidInstance, + lpEnumPlayersCallback2, lpContext, + dwFlags, bAnsi ); +} + +static HRESULT WINAPI DirectPlay2AImpl_EnumGroups + ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2, + lpContext, dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_EnumGroups + ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2, + lpContext, dwFlags, FALSE ); +} + +static HRESULT WINAPI DP_IF_EnumPlayers + ( IDirectPlay2Impl* This, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ) +{ + return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance, + lpEnumPlayersCallback2, lpContext, + dwFlags, bAnsi ); +} + +static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers + ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2, + lpContext, dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers + ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2, + lpContext, dwFlags, FALSE ); +} + +/* This function should call the registered callback function that the user + passed into EnumSessions for each entry available. + */ +static void DP_InvokeEnumSessionCallbacks + ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, + LPVOID lpNSInfo, + DWORD dwTimeout, + LPVOID lpContext ) +{ + LPDPSESSIONDESC2 lpSessionDesc; + + FIXME( ": not checking for conditions\n" ); + + /* Not sure if this should be pruning but it's convenient */ + NS_PruneSessionCache( lpNSInfo ); + + NS_ResetSessionEnumeration( lpNSInfo ); + + /* Enumerate all sessions */ + /* FIXME: Need to indicate ANSI */ + 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 ); + + for( ;; ) + { + HRESULT hr; + + /* Sleep up to dwTimeout waiting for request to terminate thread */ + if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 ) + { + TRACE( "Thread terminating on terminate request\n" ); + break; + } + + /* Now resend the enum request */ + hr = NS_SendSessionRequestBroadcast( &data->requestGuid, + data->dwEnumSessionFlags, + data->lpSpData ); + + if( FAILED(hr) ) + { + ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) ); + /* FIXME: Should we kill this thread? How to inform the main thread? */ + } + + } + + TRACE( "Thread terminating\n" ); + + /* Clean up the thread data */ + CloseHandle( hSuicideRequest ); + HeapFree( GetProcessHeap(), 0, lpContext ); + + /* FIXME: Need to have some notification to main app thread that this is + * dead. It would serve two purposes. 1) allow sync on termination + * so that we don't actually send something to ourselves when we + * become name server (race condition) and 2) so that if we die + * abnormally something else will be able to tell. + */ + + 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 %p\n", + This->dp2->hEnumSessionThread ); + + /* 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 DP_IF_EnumSessions + ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, + LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, + LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ) +{ + HRESULT hr = DP_OK; + + TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx,%u)\n", + This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags, + bAnsi ); + + /* Can't enumerate if the interface is already open */ + if( This->dp2->bConnectionOpen ) + { + return DPERR_GENERIC; + } + +#if 1 + /* The loading of a lobby provider _seems_ to require a backdoor loading + * of the service provider to also associate with this DP object. This is + * because the app doesn't seem to have to call EnumConnections and + * InitializeConnection for the SP before calling this method. As such + * we'll do their dirty work for them with a quick hack so as to always + * load the TCP/IP service provider. + * + * The correct solution would seem to involve creating a dialog box which + * contains the possible SPs. These dialog boxes most likely follow SDK + * examples. + */ + if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized ) + { + LPVOID lpConnection; + DWORD dwSize; + + WARN( "Hack providing TCP/IP SP for lobby provider activated\n" ); + + if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) ) + { + ERR( "Can't build compound addr\n" ); + return DPERR_GENERIC; + } + + hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection, + 0, bAnsi ); + if( FAILED(hr) ) + { + return hr; + } + + /* Free up the address buffer */ + HeapFree( GetProcessHeap(), 0, lpConnection ); + + /* The SP is now initialized */ + This->dp2->bSPInitialized = TRUE; + } +#endif + + + /* Use the service provider default? */ + if( dwTimeout == 0 ) + { + DPCAPS spCaps; + spCaps.dwSize = sizeof( spCaps ); + + DP_IF_GetCaps( This, &spCaps, 0 ); + dwTimeout = spCaps.dwTimeout; + + /* The service provider doesn't provide one either! */ + if( dwTimeout == 0 ) + { + /* Provide the TCP/IP default */ + dwTimeout = DPMSG_WAIT_5_SECS; + } + } + + 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_InvokeEnumSessionCallbacks( 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; + + /* Send the first enum request inline since the user may cancel a dialog + * if one is presented. Also, may also have a connecting return code. + */ + hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication, + dwFlags, &This->dp2->spData ); + + if( !FAILED(hr) ) + { + EnumSessionAsyncCallbackData* lpData + = 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 = + CreateEventW( 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_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2, + This->dp2->lpNameServerData, dwTimeout, + lpContext ); + } + + return hr; +} + +static HRESULT WINAPI DirectPlay2AImpl_EnumSessions + ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, + LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, + LPVOID lpContext, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2, + lpContext, dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_EnumSessions + ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, + LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, + LPVOID lpContext, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2, + lpContext, dwFlags, FALSE ); +} + +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 DP_IF_GetCaps + ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags ) +{ + return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags ); +} + +static HRESULT WINAPI DirectPlay2AImpl_GetCaps + ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetCaps( This, lpDPCaps, dwFlags ); +} + +static HRESULT WINAPI DirectPlay2WImpl_GetCaps + ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetCaps( This, lpDPCaps, dwFlags ); +} + +static HRESULT WINAPI DP_IF_GetGroupData + ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, + LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi ) +{ + lpGroupData lpGData; + DWORD dwRequiredBufferSize; + LPVOID lpCopyDataFrom; + + TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n", + This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi ); + + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + /* How much buffer is required? */ + if( dwFlags & DPSET_LOCAL ) + { + dwRequiredBufferSize = lpGData->dwLocalDataSize; + lpCopyDataFrom = lpGData->lpLocalData; + } + else + { + dwRequiredBufferSize = lpGData->dwRemoteDataSize; + lpCopyDataFrom = lpGData->lpRemoteData; + } + + /* Is the user requesting to know how big a buffer is required? */ + if( ( lpData == NULL ) || + ( *lpdwDataSize < dwRequiredBufferSize ) + ) + { + *lpdwDataSize = dwRequiredBufferSize; + return DPERR_BUFFERTOOSMALL; + } + + CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize ); + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay2AImpl_GetGroupData + ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData, + LPDWORD lpdwDataSize, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize, + dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_GetGroupData + ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, + LPDWORD lpdwDataSize, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize, + dwFlags, FALSE ); +} + +static HRESULT WINAPI DP_IF_GetGroupName + ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, + LPDWORD lpdwDataSize, BOOL bAnsi ) +{ + lpGroupData lpGData; + LPDPNAME lpName = (LPDPNAME)lpData; + DWORD dwRequiredDataSize; + + FIXME("(%p)->(0x%08lx,%p,%p,%u) ANSI ignored\n", + This, idGroup, lpData, lpdwDataSize, bAnsi ); + + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + dwRequiredDataSize = lpGData->name.dwSize; + + if( lpGData->name.lpszShortNameA ) + { + dwRequiredDataSize += strlen( lpGData->name.lpszShortNameA ) + 1; + } + + if( lpGData->name.lpszLongNameA ) + { + dwRequiredDataSize += strlen( lpGData->name.lpszLongNameA ) + 1; + } + + if( ( lpData == NULL ) || + ( *lpdwDataSize < dwRequiredDataSize ) + ) + { + *lpdwDataSize = dwRequiredDataSize; + return DPERR_BUFFERTOOSMALL; + } + + /* Copy the structure */ + CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize ); + + if( lpGData->name.lpszShortNameA ) + { + strcpy( ((char*)lpName)+lpGData->name.dwSize, + lpGData->name.lpszShortNameA ); + } + else + { + lpName->lpszShortNameA = NULL; + } + + if( lpGData->name.lpszShortNameA ) + { + strcpy( ((char*)lpName)+lpGData->name.dwSize, + lpGData->name.lpszLongNameA ); + } + else + { + lpName->lpszLongNameA = NULL; + } + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay2AImpl_GetGroupName + ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData, + LPDWORD lpdwDataSize ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_GetGroupName + ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, + LPDWORD lpdwDataSize ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + 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 ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount + ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE ); +} + +static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress + ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress + ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps + ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps, + DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags ); +} + +static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps + ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps, + DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags ); +} + +static HRESULT WINAPI DP_IF_GetPlayerData + ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, + LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi ) +{ + lpPlayerList lpPList; + DWORD dwRequiredBufferSize; + LPVOID lpCopyDataFrom; + + TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n", + This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi ); + + if( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + + if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL ) + { + return DPERR_INVALIDPLAYER; + } + + /* How much buffer is required? */ + if( dwFlags & DPSET_LOCAL ) + { + dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize; + lpCopyDataFrom = lpPList->lpPData->lpLocalData; + } + else + { + dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize; + lpCopyDataFrom = lpPList->lpPData->lpRemoteData; + } + + /* Is the user requesting to know how big a buffer is required? */ + if( ( lpData == NULL ) || + ( *lpdwDataSize < dwRequiredBufferSize ) + ) + { + *lpdwDataSize = dwRequiredBufferSize; + return DPERR_BUFFERTOOSMALL; + } + + CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize ); + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData + ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, + LPDWORD lpdwDataSize, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize, + dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData + ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, + LPDWORD lpdwDataSize, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize, + dwFlags, FALSE ); +} + +static HRESULT WINAPI DP_IF_GetPlayerName + ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, + LPDWORD lpdwDataSize, BOOL bAnsi ) +{ + lpPlayerList lpPList; + LPDPNAME lpName = (LPDPNAME)lpData; + DWORD dwRequiredDataSize; + + FIXME( "(%p)->(0x%08lx,%p,%p,%u): ANSI \n", + This, idPlayer, lpData, lpdwDataSize, bAnsi ); + + if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL ) + { + return DPERR_INVALIDPLAYER; + } + + dwRequiredDataSize = lpPList->lpPData->name.dwSize; + + if( lpPList->lpPData->name.lpszShortNameA ) + { + dwRequiredDataSize += strlen( lpPList->lpPData->name.lpszShortNameA ) + 1; + } + + if( lpPList->lpPData->name.lpszLongNameA ) + { + dwRequiredDataSize += strlen( lpPList->lpPData->name.lpszLongNameA ) + 1; + } + + if( ( lpData == NULL ) || + ( *lpdwDataSize < dwRequiredDataSize ) + ) + { + *lpdwDataSize = dwRequiredDataSize; + return DPERR_BUFFERTOOSMALL; + } + + /* Copy the structure */ + CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize ); + + if( lpPList->lpPData->name.lpszShortNameA ) + { + strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize, + lpPList->lpPData->name.lpszShortNameA ); + } + else + { + lpName->lpszShortNameA = NULL; + } + + if( lpPList->lpPData->name.lpszShortNameA ) + { + strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize, + lpPList->lpPData->name.lpszLongNameA ); + } + else + { + lpName->lpszLongNameA = NULL; + } + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName + ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, + LPDWORD lpdwDataSize ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName + ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, + LPDWORD lpdwDataSize ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + 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( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + + 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 ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc + ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE ); +} + +/* Intended only for COM compatibility. Always returns an error. */ +static HRESULT WINAPI DirectPlay2AImpl_Initialize + ( LPDIRECTPLAY2A iface, LPGUID lpGUID ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + TRACE("(%p)->(%p): stub\n", This, lpGUID ); + return DPERR_ALREADYINITIALIZED; +} + +/* Intended only for COM compatibility. Always returns an error. */ +static HRESULT WINAPI DirectPlay2WImpl_Initialize + ( LPDIRECTPLAY2 iface, LPGUID lpGUID ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + TRACE("(%p)->(%p): stub\n", This, lpGUID ); + return DPERR_ALREADYINITIALIZED; +} + + +static HRESULT WINAPI DP_SecureOpen + ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags, + LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials, + BOOL bAnsi ) +{ + HRESULT hr = DP_OK; + + FIXME( "(%p)->(%p,0x%08lx,%p,%p): partial stub\n", + This, lpsd, dwFlags, lpSecurity, lpCredentials ); + + if( This->dp2->bConnectionOpen ) + { + TRACE( ": rejecting already open connection.\n" ); + return DPERR_ALREADYINITIALIZED; + } + + /* If we're enumerating, kill the thread */ + DP_KillEnumSessionThread( This ); + + if( 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->lpNameServerData ); + + 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; + } + } + + /* Invoke the conditional callback for the service provider */ + if( This->dp2->spData.lpCB->Open ) + { + 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); + if( FAILED( hr ) ) + { + ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) ); + return hr; + } + } + + { + /* Create the system group of which everything is a part of */ + DPID systemGroup = DPID_SYSTEM_GROUP; + + hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL, + NULL, 0, 0, TRUE ); + + } + + if( dwFlags & DPOPEN_JOIN ) + { + DPID dpidServerId = DPID_UNKNOWN; + + /* 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 | DPPLAYER_LOCAL , 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 ); + } + + if( FAILED(hr) ) + { + ERR( "Couldn't create name server/system player: %s\n", + DPLAYX_HresultToString(hr) ); + } + + return hr; +} + +static HRESULT WINAPI DirectPlay2AImpl_Open + ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags ); + return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_Open + ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags ); + 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( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + + 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 ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + 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 ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + 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 ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + 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 ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + 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 ) +{ + lpGroupData lpGData; + + TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n", + This, idGroup, lpData, dwDataSize, dwFlags, bAnsi ); + + /* Parameter check */ + if( ( lpData == NULL ) && + ( dwDataSize != 0 ) + ) + { + return DPERR_INVALIDPARAMS; + } + + /* Find the pointer to the data for this player */ + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + { + return DPERR_INVALIDOBJECT; + } + + if( !(dwFlags & DPSET_LOCAL) ) + { + 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_LOCAL) ) + { + FIXME( "Send msg?\n" ); + } + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay2AImpl_SetGroupData + ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData, + DWORD dwDataSize, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_SetGroupData + ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, + DWORD dwDataSize, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE ); +} + +static HRESULT WINAPI DP_IF_SetGroupName + ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName, + DWORD dwFlags, BOOL bAnsi ) +{ + lpGroupData lpGData; + + TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", This, idGroup, + lpGroupName, dwFlags, bAnsi ); + + if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi ); + + /* Should send a DPMSG_SETPLAYERORGROUPNAME message */ + FIXME( "Message not sent and dwFlags ignored\n" ); + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay2AImpl_SetGroupName + ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName, + DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_SetGroupName + ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName, + DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE ); +} + +static HRESULT WINAPI DP_IF_SetPlayerData + ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, + DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi ) +{ + lpPlayerList lpPList; + + TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n", + This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi ); + + /* Parameter check */ + if( ( lpData == NULL ) && + ( dwDataSize != 0 ) + ) + { + return DPERR_INVALIDPARAMS; + } + + /* Find the pointer to the data for this player */ + if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL ) + { + return DPERR_INVALIDPLAYER; + } + + if( !(dwFlags & DPSET_LOCAL) ) + { + 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_LOCAL) ) + { + FIXME( "Send msg?\n" ); + } + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData + ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, + DWORD dwDataSize, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize, + dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData + ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, + DWORD dwDataSize, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize, + dwFlags, FALSE ); +} + +static HRESULT WINAPI DP_IF_SetPlayerName + ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName, + DWORD dwFlags, BOOL bAnsi ) +{ + lpPlayerList lpPList; + + TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", + This, idPlayer, lpPlayerName, dwFlags, bAnsi ); + + if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi ); + + /* Should send a DPMSG_SETPLAYERORGROUPNAME message */ + FIXME( "Message not sent and dwFlags ignored\n" ); + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName + ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName, + DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName + ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName, + DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + 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( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + + 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 = 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 ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE ); +} + +static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc + ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; + 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->lpszSessionNameA ) + { + dwSize += lstrlenA( lpSessDesc->lpszSessionNameA ) + 1; + } + + if( lpSessDesc->lpszPasswordA ) + { + dwSize += lstrlenA( lpSessDesc->lpszPasswordA ) + 1; + } + } + else /* UNICODE */ + { + if( lpSessDesc->lpszSessionName ) + { + dwSize += sizeof( WCHAR ) * + ( lstrlenW( lpSessDesc->lpszSessionName ) + 1 ); + } + + if( lpSessDesc->lpszPassword ) + { + dwSize += sizeof( WCHAR ) * + ( lstrlenW( lpSessDesc->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->lpszSessionNameA ) + { + lstrcpyA( (LPSTR)lpStartOfFreeSpace, + lpSessionDest->lpszSessionNameA ); + lpSessionDest->lpszSessionNameA = (LPSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += + lstrlenA( (LPSTR)lpSessionDest->lpszSessionNameA ) + 1; + } + + if( lpSessionSrc->lpszPasswordA ) + { + lstrcpyA( (LPSTR)lpStartOfFreeSpace, + lpSessionDest->lpszPasswordA ); + lpSessionDest->lpszPasswordA = (LPSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += + lstrlenA( (LPSTR)lpSessionDest->lpszPasswordA ) + 1; + } + } + else /* UNICODE */ + { + if( lpSessionSrc->lpszSessionName ) + { + lstrcpyW( (LPWSTR)lpStartOfFreeSpace, + lpSessionDest->lpszSessionName ); + lpSessionDest->lpszSessionName = (LPWSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof(WCHAR) * + ( lstrlenW( (LPWSTR)lpSessionDest->lpszSessionName ) + 1 ); + } + + if( lpSessionSrc->lpszPassword ) + { + lstrcpyW( (LPWSTR)lpStartOfFreeSpace, + lpSessionDest->lpszPassword ); + lpSessionDest->lpszPassword = (LPWSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof(WCHAR) * + ( lstrlenW( (LPWSTR)lpSessionDest->lpszPassword ) + 1 ); + } + } +} + + +static HRESULT WINAPI DP_IF_AddGroupToGroup + ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup ) +{ + lpGroupData lpGParentData; + lpGroupData lpGData; + lpGroupList lpNewGList; + + TRACE( "(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup ); + + if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + /* Create a player list (ie "shortcut" ) */ + lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) ); + if( lpNewGList == NULL ) + { + return DPERR_CANTADDPLAYER; + } + + /* Add the shortcut */ + lpGData->uRef++; + lpNewGList->lpGData = lpGData; + + /* Add the player to the list of players for this group */ + DPQ_INSERT( lpGData->groups, lpNewGList, groups ); + + /* Send a ADDGROUPTOGROUP message */ + FIXME( "Not sending message\n" ); + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup + ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup ); +} + +static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup + ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup ); +} + +static HRESULT WINAPI DP_IF_CreateGroupInGroup + ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup, + LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData, + DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi ) +{ + lpGroupData lpGParentData; + lpGroupList lpGList; + lpGroupData lpGData; + + TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,%u)\n", + This, idParentGroup, lpidGroup, lpGroupName, lpData, + dwDataSize, dwFlags, bAnsi ); + + /* Verify that the specified parent is valid */ + if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, + idParentGroup ) ) == NULL + ) + { + return DPERR_INVALIDGROUP; + } + + lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName, + dwFlags, idParentGroup, bAnsi ); + + if( lpGData == NULL ) + { + return DPERR_CANTADDPLAYER; /* yes player not group */ + } + + /* Something else is referencing this data */ + lpGData->uRef++; + + 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 */ + lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) ); + if( lpGList == NULL ) + { + FIXME( "Memory leak\n" ); + return DPERR_CANTADDPLAYER; /* yes player not group */ + } + + lpGList->lpGData = lpGData; + + DPQ_INSERT( lpGParentData->groups, lpGList, groups ); + + /* 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; +} + +static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup + ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup, + LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, + DWORD dwFlags ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + + *lpidGroup = DPID_UNKNOWN; + + return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, + lpGroupName, lpData, dwDataSize, dwFlags, + TRUE ); +} + +static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup + ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup, + LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, + DWORD dwFlags ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + + *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; + lpGroupData lpGParentData; + + TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup ); + + /* Is the parent group valid? */ + if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + /* Remove the group from the parent group queue */ + DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList ); + + if( lpGList == NULL ) + { + return DPERR_INVALIDGROUP; + } + + /* Decrement the ref count */ + lpGList->lpGData->uRef--; + + /* Free up the list item */ + HeapFree( GetProcessHeap(), 0, lpGList ); + + /* Should send a DELETEGROUPFROMGROUP message */ + FIXME( "message not sent\n" ); + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup + ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup ); +} + +static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup + ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup ); +} + +static +BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf, + LPDWORD lpdwBufSize ) +{ + DPCOMPOUNDADDRESSELEMENT dpCompoundAddress; + HRESULT hr; + + dpCompoundAddress.dwDataSize = sizeof( GUID ); + memcpy( &dpCompoundAddress.guidDataType, &DPAID_ServiceProvider, + sizeof( GUID ) ) ; + dpCompoundAddress.lpData = lpcSpGuid; + + *lplpAddrBuf = NULL; + *lpdwBufSize = 0; + + hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf, + lpdwBufSize, TRUE ); + + if( hr != DPERR_BUFFERTOOSMALL ) + { + ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) ); + return FALSE; + } + + /* Now allocate the buffer */ + *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + *lpdwBufSize ); + + hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf, + lpdwBufSize, TRUE ); + if( FAILED(hr) ) + { + ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) ); + return FALSE; + } + + return TRUE; +} + +static HRESULT WINAPI DirectPlay3AImpl_EnumConnections + ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + TRACE("(%p)->(%p,%p,%p,0x%08lx)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags ); + + /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */ + if( dwFlags == 0 ) + { + dwFlags = DPCONNECTION_DIRECTPLAY; + } + + if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) || + ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) ) + ) + { + return DPERR_INVALIDFLAGS; + } + + if( !lpEnumCallback || !*lpEnumCallback ) + { + return DPERR_INVALIDPARAMS; + } + + /* Enumerate DirectPlay service providers */ + if( dwFlags & DPCONNECTION_DIRECTPLAY ) + { + HKEY hkResult; + LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers"; + LPCSTR guidDataSubKey = "Guid"; + char subKeyName[51]; + DWORD dwIndex, sizeOfSubKeyName=50; + FILETIME filetime; + + /* 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 DP_OK; + } + + + /* 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 returnTypeGUID, sizeOfReturnBuffer = 50; + char returnBuffer[51]; + WCHAR buff[51]; + DPNAME dpName; + BOOL bBuildPass; + + LPVOID lpAddressBuffer = NULL; + DWORD dwAddressBufferSize = 0; + + 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, &returnTypeGUID, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR(": missing GUID registry data members\n" ); + continue; + } + + /* FIXME: Check return types to ensure we're interpreting data right */ + MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) ); + CLSIDFromString( buff, &serviceProviderGUID ); + /* FIXME: Have I got a memory leak on the serviceProviderGUID? */ + + /* Fill in the DPNAME struct for the service provider */ + dpName.dwSize = sizeof( dpName ); + dpName.dwFlags = 0; + dpName.lpszShortNameA = subKeyName; + dpName.lpszLongNameA = NULL; + + /* Create the compound address for the service provider. + * NOTE: This is a gruesome architectural scar right now. DP + * uses DPL and DPL uses DP. Nasty stuff. This may be why the + * native dll just gets around this little bit by allocating an + * 80 byte buffer which isn't even 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 :) */ + + bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID, + &lpAddressBuffer, + &dwAddressBufferSize ); + if( !bBuildPass ) + { + ERR( "Can't build compound addr\n" ); + return DPERR_GENERIC; + } + + /* The enumeration will return FALSE if we are not to continue */ + if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize, + &dpName, DPCONNECTION_DIRECTPLAY, lpContext ) ) + { + return DP_OK; + } + } + } + + /* Enumerate DirectPlayLobby service providers */ + if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) + { + HKEY hkResult; + LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers"; + LPCSTR guidDataSubKey = "Guid"; + char subKeyName[51]; + DWORD dwIndex, sizeOfSubKeyName=50; + FILETIME filetime; + + /* 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 DP_OK; + } + + + /* Traverse all the lobby 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 returnTypeGUID, sizeOfReturnBuffer = 50; + char returnBuffer[51]; + WCHAR buff[51]; + DPNAME dpName; + HRESULT hr; + + DPCOMPOUNDADDRESSELEMENT dpCompoundAddress; + LPVOID lpAddressBuffer = NULL; + DWORD dwAddressBufferSize = 0; + + 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, &returnTypeGUID, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR(": missing GUID registry data members\n" ); + continue; + } + + /* FIXME: Check return types to ensure we're interpreting data right */ + MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) ); + CLSIDFromString( buff, &serviceProviderGUID ); + /* FIXME: Have I got a memory leak on the serviceProviderGUID? */ + + /* Fill in the DPNAME struct for the service provider */ + dpName.dwSize = sizeof( dpName ); + dpName.dwFlags = 0; + dpName.lpszShortNameA = subKeyName; + dpName.lpszLongNameA = NULL; + + /* Create the compound address for the service provider. + NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP + nast stuff. This may be why the native dll just gets around this little bit by + 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_LobbyProvider; + dpCompoundAddress.dwDataSize = sizeof( GUID ); + dpCompoundAddress.lpData = &serviceProviderGUID; + + if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer, + &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL ) + { + ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) ); + return hr; + } + + /* Now allocate the buffer */ + lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize ); + + if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer, + &dwAddressBufferSize, TRUE ) ) != DP_OK ) + { + ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) ); + return hr; + } + + /* The enumeration will return FALSE if we are not to continue */ + if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize, + &dpName, DPCONNECTION_DIRECTPLAYLOBBY, lpContext ) ) + { + return DP_OK; + } + } + } + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3WImpl_EnumConnections + ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(%p,%p,%p,0x%08lx): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags ); + return DP_OK; +} + +static HRESULT WINAPI DP_IF_EnumGroupsInGroup + ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, + LPVOID lpContext, DWORD dwFlags, BOOL bAnsi ) +{ + lpGroupList lpGList; + lpGroupData lpGData; + + FIXME( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n", + This, idGroup, lpguidInstance, lpEnumPlayersCallback2, + lpContext, dwFlags, bAnsi ); + + if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + if( DPQ_IS_EMPTY( lpGData->groups ) ) + { + return DP_OK; + } + + 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 ); + + } + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup + ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance, + LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, + DWORD dwFlags ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + 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 ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance, + lpEnumPlayersCallback2, lpContext, dwFlags, + FALSE ); +} + +static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings + ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings + ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize ); + return DP_OK; +} + +static 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, LPBOOL lpbIsDpSp ) +{ + 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 ); + *lpbIsDpSp = (i == 0) ? TRUE : FALSE; + + + /* 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]; + WCHAR buff[51]; + DWORD dwTemp, len; + + 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, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR(": missing GUID registry data members\n" ); + continue; + } + + /* FIXME: Check return types to ensure we're interpreting data right */ + MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) ); + CLSIDFromString( buff, &serviceProviderGUID ); + /* 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; + } + + if( i == 0 ) /* DP SP */ + { + len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 ); + lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len ); + } + + sizeOfReturnBuffer = 255; + + /* Get dwReserved1 */ + if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey, + NULL, &returnType, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR(": missing dwReserved1 registry data members\n") ; + continue; + } + + if( i == 0 ) + memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) ); + + sizeOfReturnBuffer = 255; + + /* Get dwReserved2 */ + if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey, + NULL, &returnType, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR(": missing dwReserved1 registry data members\n") ; + continue; + } + + if( i == 0 ) + memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) ); + + sizeOfReturnBuffer = 255; + + /* Get the path for this service provider */ + if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey, + NULL, NULL, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) ) != ERROR_SUCCESS ) + { + ERR(": missing PATH registry data members: 0x%08lx\n", dwTemp ); + continue; + } + + TRACE( "Loading %s\n", returnBuffer ); + return LoadLibraryA( returnBuffer ); + } + } + + return 0; +} + +static +HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider ) +{ + HRESULT hr; + LPDPSP_SPINIT SPInit; + + /* Initialize the service provider by calling SPInit */ + SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" ); + + if( SPInit == NULL ) + { + ERR( "Service provider doesn't provide SPInit interface?\n" ); + FreeLibrary( hServiceProvider ); + return DPERR_UNAVAILABLE; + } + + TRACE( "Calling SPInit (DP SP entry point)\n" ); + + hr = (*SPInit)( &This->dp2->spData ); + + if( FAILED(hr) ) + { + ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) ); + FreeLibrary( hServiceProvider ); + return hr; + } + + /* FIXME: Need to verify the sanity of the returned callback table + * using IsBadCodePtr */ + This->dp2->bSPInitialized = TRUE; + + /* This interface is now initialized as a DP object */ + This->dp2->connectionInitialized = DP_SERVICE_PROVIDER; + + /* Store the handle of the module so that we can unload it later */ + This->dp2->hServiceProvider = hServiceProvider; + + return hr; +} + +static +HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider ) +{ + HRESULT hr; + LPSP_INIT DPLSPInit; + + /* Initialize the service provider by calling SPInit */ + DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" ); + + if( DPLSPInit == NULL ) + { + ERR( "Service provider doesn't provide DPLSPInit interface?\n" ); + FreeLibrary( hLobbyProvider ); + return DPERR_UNAVAILABLE; + } + + TRACE( "Calling DPLSPInit (DPL SP entry point)\n" ); + + hr = (*DPLSPInit)( &This->dp2->dplspData ); + + if( FAILED(hr) ) + { + ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) ); + FreeLibrary( hLobbyProvider ); + return hr; + } + + /* FIXME: Need to verify the sanity of the returned callback table + * using IsBadCodePtr */ + + This->dp2->bDPLSPInitialized = TRUE; + + /* This interface is now initialized as a lobby object */ + This->dp2->connectionInitialized = DP_LOBBY_PROVIDER; + + /* Store the handle of the module so that we can unload it later */ + This->dp2->hDPLobbyProvider = hLobbyProvider; + + return hr; +} + +static HRESULT WINAPI DP_IF_InitializeConnection + ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi ) +{ + HMODULE hServiceProvider; + HRESULT hr; + GUID guidSP; + const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */ + BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */ + + TRACE("(%p)->(%p,0x%08lx,%u)\n", This, lpConnection, dwFlags, bAnsi ); + + if( dwFlags != 0 ) + { + return DPERR_INVALIDFLAGS; + } + + /* Find out what the requested SP is and how large this buffer is */ + hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection, + dwAddrSize, &guidSP ); + + if( FAILED(hr) ) + { + ERR( "Invalid compound address?\n" ); + return DPERR_UNAVAILABLE; + } + + /* Load the service provider */ + hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp ); + + if( hServiceProvider == 0 ) + { + ERR( "Unable to load service provider\n" ); + return DPERR_UNAVAILABLE; + } + + if( bIsDpSp ) + { + /* Fill in what we can of the Service Provider required information. + * The rest was be done in DP_LoadSP + */ + This->dp2->spData.lpAddress = lpConnection; + This->dp2->spData.dwAddressSize = dwAddrSize; + This->dp2->spData.lpGuid = &guidSP; + + hr = DP_InitializeDPSP( This, hServiceProvider ); + } + else + { + This->dp2->dplspData.lpAddress = lpConnection; + + hr = DP_InitializeDPLSP( This, hServiceProvider ); + } + + if( FAILED(hr) ) + { + return hr; + } + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection + ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + + /* This may not be externally invoked once either an SP or LP is initialized */ + if( This->dp2->connectionInitialized != NO_PROVIDER ) + { + return DPERR_ALREADYINITIALIZED; + } + + return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE ); +} + +static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection + ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + + /* This may not be externally invoked once either an SP or LP is initialized */ + if( This->dp2->connectionInitialized != NO_PROVIDER ) + { + return DPERR_ALREADYINITIALIZED; + } + + return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE ); +} + +static HRESULT WINAPI DirectPlay3AImpl_SecureOpen + ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags, + LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */ + return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE ); +} + +static HRESULT WINAPI DirectPlay3WImpl_SecureOpen + ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags, + LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials ) +{ + IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */ + return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE ); +} + +static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage + ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage + ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings + ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings + ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3AImpl_StartSession + ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3WImpl_StartSession + ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags + ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags + ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags ); + return DP_OK; +} + +static HRESULT WINAPI DP_IF_GetGroupParent + ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup, + BOOL bAnsi ) +{ + lpGroupData lpGData; + + TRACE("(%p)->(0x%08lx,%p,%u)\n", This, idGroup, lpidGroup, bAnsi ); + + if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL ) + { + return DPERR_INVALIDGROUP; + } + + *lpidGroup = lpGData->dpid; + + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent + ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE ); +} +static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent + ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE ); +} + +static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount + ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount + ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags + ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags + ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags ) +{ + IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface; + FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner + ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner ) +{ + IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface; + FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner + ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner ) +{ + IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface; + FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner + ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner ) +{ + IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner ); + return DP_OK; +} + +static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner + ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner ) +{ + IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface; + FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner ); + return DP_OK; +} + +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 ) +{ + 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 service 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 0 + if( bExpectReply ) + { + DWORD dwWaitReturn; + + This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL ); + + dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout ); + if( dwWaitReturn != WAIT_OBJECT_0 ) + { + ERR( "Wait failed 0x%08lx\n", dwWaitReturn ); + } + } +#endif + } + + 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 ) +{ + IDirectPlay2Impl *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 ) +{ + IDirectPlay2Impl *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\n" ); + + /* FIXME: This queuing should only be for async messages */ + + lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) ); + lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize ); + + CopyMemory( lpMElem->msg, lpData, dwDataSize ); + + /* FIXME: Need to queue based on priority */ + 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 ) +{ + IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface; + 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 ) +{ + IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface; + 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 ) +{ + IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface; + + 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 ) +{ + IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface; + + 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 ) +{ + IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface; + + 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 ) +{ + IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface; + + 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 */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlay2WVT.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static const IDirectPlay2Vtbl directPlay2WVT = +{ + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, + + DirectPlay2WImpl_AddPlayerToGroup, + DirectPlay2WImpl_Close, + DirectPlay2WImpl_CreateGroup, + DirectPlay2WImpl_CreatePlayer, + DirectPlay2WImpl_DeletePlayerFromGroup, + DirectPlay2WImpl_DestroyGroup, + DirectPlay2WImpl_DestroyPlayer, + DirectPlay2WImpl_EnumGroupPlayers, + DirectPlay2WImpl_EnumGroups, + DirectPlay2WImpl_EnumPlayers, + DirectPlay2WImpl_EnumSessions, + DirectPlay2WImpl_GetCaps, + DirectPlay2WImpl_GetGroupData, + DirectPlay2WImpl_GetGroupName, + DirectPlay2WImpl_GetMessageCount, + DirectPlay2WImpl_GetPlayerAddress, + DirectPlay2WImpl_GetPlayerCaps, + DirectPlay2WImpl_GetPlayerData, + DirectPlay2WImpl_GetPlayerName, + DirectPlay2WImpl_GetSessionDesc, + DirectPlay2WImpl_Initialize, + DirectPlay2WImpl_Open, + DirectPlay2WImpl_Receive, + DirectPlay2WImpl_Send, + DirectPlay2WImpl_SetGroupData, + DirectPlay2WImpl_SetGroupName, + DirectPlay2WImpl_SetPlayerData, + DirectPlay2WImpl_SetPlayerName, + DirectPlay2WImpl_SetSessionDesc +}; +#undef XCAST + +/* Note: Hack so we can reuse the old functions without compiler warnings */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlay2AVT.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static const IDirectPlay2Vtbl directPlay2AVT = +{ + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, + + DirectPlay2AImpl_AddPlayerToGroup, + DirectPlay2AImpl_Close, + DirectPlay2AImpl_CreateGroup, + DirectPlay2AImpl_CreatePlayer, + DirectPlay2AImpl_DeletePlayerFromGroup, + DirectPlay2AImpl_DestroyGroup, + DirectPlay2AImpl_DestroyPlayer, + DirectPlay2AImpl_EnumGroupPlayers, + DirectPlay2AImpl_EnumGroups, + DirectPlay2AImpl_EnumPlayers, + DirectPlay2AImpl_EnumSessions, + DirectPlay2AImpl_GetCaps, + DirectPlay2AImpl_GetGroupData, + DirectPlay2AImpl_GetGroupName, + DirectPlay2AImpl_GetMessageCount, + DirectPlay2AImpl_GetPlayerAddress, + DirectPlay2AImpl_GetPlayerCaps, + DirectPlay2AImpl_GetPlayerData, + DirectPlay2AImpl_GetPlayerName, + DirectPlay2AImpl_GetSessionDesc, + DirectPlay2AImpl_Initialize, + DirectPlay2AImpl_Open, + DirectPlay2AImpl_Receive, + DirectPlay2AImpl_Send, + DirectPlay2AImpl_SetGroupData, + DirectPlay2AImpl_SetGroupName, + DirectPlay2AImpl_SetPlayerData, + DirectPlay2AImpl_SetPlayerName, + DirectPlay2AImpl_SetSessionDesc +}; +#undef XCAST + + +/* Note: Hack so we can reuse the old functions without compiler warnings */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlay3AVT.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static const IDirectPlay3Vtbl directPlay3AVT = +{ + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, + + XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup, + XCAST(Close)DirectPlay2AImpl_Close, + XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup, + XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer, + XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup, + XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup, + XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer, + XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers, + XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups, + XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers, + XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions, + XCAST(GetCaps)DirectPlay2AImpl_GetCaps, + XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData, + XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName, + XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount, + XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress, + XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps, + XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData, + XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName, + XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc, + XCAST(Initialize)DirectPlay2AImpl_Initialize, + XCAST(Open)DirectPlay2AImpl_Open, + XCAST(Receive)DirectPlay2AImpl_Receive, + XCAST(Send)DirectPlay2AImpl_Send, + XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData, + XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName, + XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData, + XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName, + XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc, + + DirectPlay3AImpl_AddGroupToGroup, + DirectPlay3AImpl_CreateGroupInGroup, + DirectPlay3AImpl_DeleteGroupFromGroup, + DirectPlay3AImpl_EnumConnections, + DirectPlay3AImpl_EnumGroupsInGroup, + DirectPlay3AImpl_GetGroupConnectionSettings, + DirectPlay3AImpl_InitializeConnection, + DirectPlay3AImpl_SecureOpen, + DirectPlay3AImpl_SendChatMessage, + DirectPlay3AImpl_SetGroupConnectionSettings, + DirectPlay3AImpl_StartSession, + DirectPlay3AImpl_GetGroupFlags, + DirectPlay3AImpl_GetGroupParent, + DirectPlay3AImpl_GetPlayerAccount, + DirectPlay3AImpl_GetPlayerFlags +}; +#undef XCAST + +/* Note: Hack so we can reuse the old functions without compiler warnings */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlay3WVT.fun)) +#else +# define XCAST(fun) (void*) +#endif +static const IDirectPlay3Vtbl directPlay3WVT = +{ + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, + + XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup, + XCAST(Close)DirectPlay2WImpl_Close, + XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup, + XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer, + XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup, + XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup, + XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer, + XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers, + XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups, + XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers, + XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions, + XCAST(GetCaps)DirectPlay2WImpl_GetCaps, + XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData, + XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName, + XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount, + XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress, + XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps, + XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData, + XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName, + XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc, + XCAST(Initialize)DirectPlay2WImpl_Initialize, + XCAST(Open)DirectPlay2WImpl_Open, + XCAST(Receive)DirectPlay2WImpl_Receive, + XCAST(Send)DirectPlay2WImpl_Send, + XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData, + XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName, + XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData, + XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName, + XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc, + + DirectPlay3WImpl_AddGroupToGroup, + DirectPlay3WImpl_CreateGroupInGroup, + DirectPlay3WImpl_DeleteGroupFromGroup, + DirectPlay3WImpl_EnumConnections, + DirectPlay3WImpl_EnumGroupsInGroup, + DirectPlay3WImpl_GetGroupConnectionSettings, + DirectPlay3WImpl_InitializeConnection, + DirectPlay3WImpl_SecureOpen, + DirectPlay3WImpl_SendChatMessage, + DirectPlay3WImpl_SetGroupConnectionSettings, + DirectPlay3WImpl_StartSession, + DirectPlay3WImpl_GetGroupFlags, + DirectPlay3WImpl_GetGroupParent, + DirectPlay3WImpl_GetPlayerAccount, + DirectPlay3WImpl_GetPlayerFlags +}; +#undef XCAST + +/* Note: Hack so we can reuse the old functions without compiler warnings */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlay4WVT.fun)) +#else +# define XCAST(fun) (void*) +#endif +static const IDirectPlay4Vtbl directPlay4WVT = +{ + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, + + XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup, + XCAST(Close)DirectPlay2WImpl_Close, + XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup, + XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer, + XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup, + XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup, + XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer, + XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers, + XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups, + XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers, + XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions, + XCAST(GetCaps)DirectPlay2WImpl_GetCaps, + XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData, + XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName, + XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount, + XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress, + XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps, + XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData, + XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName, + XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc, + XCAST(Initialize)DirectPlay2WImpl_Initialize, + XCAST(Open)DirectPlay2WImpl_Open, + XCAST(Receive)DirectPlay2WImpl_Receive, + XCAST(Send)DirectPlay2WImpl_Send, + XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData, + XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName, + XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData, + XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName, + XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc, + + XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup, + XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup, + XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup, + XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections, + XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup, + XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings, + XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection, + XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen, + XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage, + XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings, + XCAST(StartSession)DirectPlay3WImpl_StartSession, + XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags, + XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent, + XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount, + XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags, + + DirectPlay4WImpl_GetGroupOwner, + DirectPlay4WImpl_SetGroupOwner, + DirectPlay4WImpl_SendEx, + DirectPlay4WImpl_GetMessageQueue, + DirectPlay4WImpl_CancelMessage, + DirectPlay4WImpl_CancelPriority +}; +#undef XCAST + + +/* Note: Hack so we can reuse the old functions without compiler warnings */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlay4AVT.fun)) +#else +# define XCAST(fun) (void*) +#endif +static const IDirectPlay4Vtbl directPlay4AVT = +{ + XCAST(QueryInterface)DP_QueryInterface, + XCAST(AddRef)DP_AddRef, + XCAST(Release)DP_Release, + + XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup, + XCAST(Close)DirectPlay2AImpl_Close, + XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup, + XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer, + XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup, + XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup, + XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer, + XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers, + XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups, + XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers, + XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions, + XCAST(GetCaps)DirectPlay2AImpl_GetCaps, + XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData, + XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName, + XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount, + XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress, + XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps, + XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData, + XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName, + XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc, + XCAST(Initialize)DirectPlay2AImpl_Initialize, + XCAST(Open)DirectPlay2AImpl_Open, + XCAST(Receive)DirectPlay2AImpl_Receive, + XCAST(Send)DirectPlay2AImpl_Send, + XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData, + XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName, + XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData, + XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName, + XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc, + + XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup, + XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup, + XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup, + XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections, + XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup, + XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings, + XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection, + XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen, + XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage, + XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings, + XCAST(StartSession)DirectPlay3AImpl_StartSession, + XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags, + XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent, + XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount, + XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags, + + DirectPlay4AImpl_GetGroupOwner, + DirectPlay4AImpl_SetGroupOwner, + DirectPlay4AImpl_SendEx, + DirectPlay4AImpl_GetMessageQueue, + DirectPlay4AImpl_CancelMessage, + DirectPlay4AImpl_CancelPriority +}; +#undef XCAST + +extern +HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP, + DPID idPlayer, + LPVOID* lplpData ) +{ + lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer ); + + if( lpPlayer == NULL ) + { + return DPERR_INVALIDPLAYER; + } + + *lplpData = lpPlayer->lpPData->lpSPPlayerData; + + return DP_OK; +} + +extern +HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP, + DPID idPlayer, + LPVOID lpData ) +{ + lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer ); + + if( lpPlayer == NULL ) + { + return DPERR_INVALIDPLAYER; + } + + lpPlayer->lpPData->lpSPPlayerData = lpData; + + return DP_OK; +} + +/*************************************************************************** + * DirectPlayEnumerateAW + * + * The pointer to the structure lpContext will be filled with the + * appropriate data for each service offered by the OS. These services are + * not necessarily available on this particular machine but are defined + * as simple service providers under the "Service Providers" registry key. + * This structure is then passed to lpEnumCallback for each of the different + * services. + * + * This API is useful only for applications written using DirectX3 or + * worse. It is superseded by IDirectPlay3::EnumConnections which also + * gives information on the actual connections. + * + * defn of a service provider: + * A dynamic-link library used by DirectPlay to communicate over a network. + * The service provider contains all the network-specific code required + * to send and receive messages. Online services and network operators can + * supply service providers to use specialized hardware, protocols, communications + * media, and network resources. + * + */ +static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA, + LPDPENUMDPCALLBACKW lpEnumCallbackW, + LPVOID lpContext) +{ + HKEY hkResult; + static const WCHAR searchSubKey[] = { + 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\', + 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\', + 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\', + 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 }; + static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 }; + static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 }; + + DWORD dwIndex; + FILETIME filetime; + + char *descriptionA = NULL; + DWORD max_sizeOfDescriptionA = 0; + WCHAR *descriptionW = NULL; + DWORD max_sizeOfDescriptionW = 0; + + if (!lpEnumCallbackA && !lpEnumCallbackW) + { + return DPERR_INVALIDPARAMS; + } + + /* Need to loop over the service providers in the registry */ + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey, + 0, KEY_READ, &hkResult) != ERROR_SUCCESS) + { + /* Hmmm. Does this mean that there are no service providers? */ + ERR(": no service provider key in the registry - check your Wine installation !!!\n"); + return DPERR_GENERIC; + } + + /* Traverse all the service providers we have available */ + dwIndex = 0; + while (1) + { + WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */ + DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR); + HKEY hkServiceProvider; + GUID serviceProviderGUID; + WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ]; + DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent); + LONG ret_value; + + ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName, + NULL, NULL, NULL, &filetime); + if (ret_value == ERROR_NO_MORE_ITEMS) + break; + else if (ret_value != ERROR_SUCCESS) + { + ERR(": could not enumerate on service provider key.\n"); + return DPERR_EXCEPTION; + } + TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName)); + + /* Open the key for this service provider */ + if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS) + { + ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName)); + continue; + } + + /* Get the GUID from the registry */ + if (RegQueryValueExW(hkServiceProvider, guidKey, + NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS) + { + ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName)); + continue; + } + if (sizeOfGuidKeyContent != sizeof(guidKeyContent)) + { + ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent)); + continue; + } + CLSIDFromString(guidKeyContent, &serviceProviderGUID ); + + /* The enumeration will return FALSE if we are not to continue. + * + * Note: on my windows box, major / minor version is 6 / 0 for all service providers + * and have no relations to any of the two dwReserved1 and dwReserved2 keys. + * I think that it simply means that they are in-line with DirectX 6.0 + */ + if (lpEnumCallbackA) + { + DWORD sizeOfDescription = 0; + + /* Note that this the the A case of this function, so use the A variant to get the description string */ + if (RegQueryValueExA(hkServiceProvider, "DescriptionA", + NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS) + { + ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName)); + continue; + } + if (sizeOfDescription > max_sizeOfDescriptionA) + { + HeapFree(GetProcessHeap(), 0, descriptionA); + max_sizeOfDescriptionA = sizeOfDescription; + descriptionA = HeapAlloc(GetProcessHeap(), 0, max_sizeOfDescriptionA); + } + descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription); + RegQueryValueExA(hkServiceProvider, "DescriptionA", + NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription); + + if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext)) + goto end; + } + else + { + DWORD sizeOfDescription = 0; + + if (RegQueryValueExW(hkServiceProvider, descW, + NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS) + { + ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName)); + continue; + } + if (sizeOfDescription > max_sizeOfDescriptionW) + { + HeapFree(GetProcessHeap(), 0, descriptionW); + max_sizeOfDescriptionW = sizeOfDescription; + descriptionW = HeapAlloc(GetProcessHeap(), 0, max_sizeOfDescriptionW); + } + descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription); + RegQueryValueExW(hkServiceProvider, descW, + NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription); + + if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext)) + goto end; + } + + dwIndex++; + } + + end: + HeapFree(GetProcessHeap(), 0, descriptionA); + HeapFree(GetProcessHeap(), 0, descriptionW); + + return DP_OK; +} + +/*************************************************************************** + * DirectPlayEnumerate [DPLAYX.9] + * DirectPlayEnumerateA [DPLAYX.2] + */ +HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext ) +{ + TRACE("(%p,%p)\n", lpEnumCallback, lpContext); + + return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext); +} + +/*************************************************************************** + * DirectPlayEnumerateW [DPLAYX.3] + */ +HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext ) +{ + TRACE("(%p,%p)\n", lpEnumCallback, lpContext); + + return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext); +} + +typedef struct tagCreateEnum +{ + LPVOID lpConn; + LPCGUID lpGuid; +} CreateEnumData, *lpCreateEnumData; + +/* Find and copy the matching connection for the SP guid */ +static 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] + * + */ +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 ) + { + return CLASS_E_NOAGGREGATION; + } + + /* 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( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK ) + { + return DPERR_UNAVAILABLE; + } + + if( IsEqualGUID( &GUID_NULL, lpGUID ) ) + { + /* The GUID_NULL means don't bind a service provider. Just return the + 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) ); + + /* We're going to use a DP3 interface */ + hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A, + (LPVOID*)&lpDP3A ); + if( FAILED(hr) ) + { + ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) ); + return hr; + } + + cbData.lpConn = NULL; + cbData.lpGuid = lpGUID; + + /* 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; + } + + /* 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/reactos/lib/dplayx/dplay_global.h b/reactos/lib/dplayx/dplay_global.h new file mode 100644 index 00000000000..b7b0f0becfa --- /dev/null +++ b/reactos/lib/dplayx/dplay_global.h @@ -0,0 +1,246 @@ +/* + * Copyright 2000 Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_DPLAY_GLOBAL_INCLUDED +#define __WINE_DPLAY_GLOBAL_INCLUDED + +#include + +#include "windef.h" +#include "winbase.h" +#include "dplaysp.h" +#include "lobbysp.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 +{ + LONG ulObjRef; + CRITICAL_SECTION DP_lock; +} DirectPlayIUnknownData; + +typedef struct tagEnumSessionAsyncCallbackData +{ + LPSPINITDATA lpSpData; + GUID requestGuid; + DWORD dwEnumSessionFlags; + DWORD dwTimeout; + HANDLE hSuicideRequest; +} EnumSessionAsyncCallbackData; + +typedef struct tagDP_MSG_REPLY_STRUCT +{ + HANDLE hReceipt; + WORD wExpectedReply; + LPVOID lpReplyMsg; + DWORD dwMsgBodySize; + /* FIXME: Is the message header required as well? */ +} DP_MSG_REPLY_STRUCT, *LPDP_MSG_REPLY_STRUCT; + +typedef struct tagDP_MSG_REPLY_STRUCT_LIST +{ + DPQ_ENTRY(tagDP_MSG_REPLY_STRUCT_LIST) replysExpected; + DP_MSG_REPLY_STRUCT replyExpected; +} DP_MSG_REPLY_STRUCT_LIST, *LPDP_MSG_REPLY_STRUCT_LIST; + +struct PlayerData +{ + /* Individual player information */ + DPID dpid; + + DPNAME name; + HANDLE hEvent; + + ULONG uRef; /* What is the reference count on this data? */ + + /* View of local data */ + LPVOID lpLocalData; + DWORD dwLocalDataSize; + + /* View of remote data */ + LPVOID lpRemoteData; + DWORD dwRemoteDataSize; + + /* SP data on a per player basis */ + LPVOID lpSPPlayerData; + + 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 */ + + ULONG uRef; /* Reference count */ + + 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; + +enum SPSTATE +{ + NO_PROVIDER = 0, + DP_SERVICE_PROVIDER = 1, + DP_LOBBY_PROVIDER = 2 +}; + +/* Contains all data members. FIXME: Rename me */ +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 */ + + lpGroupData lpSysGroup; /* System group with _everything_ in it */ + + 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; + BOOL bSPInitialized; + + /* Information about the lobby server that's attached to this DP object */ + SPDATA_INIT dplspData; + BOOL bDPLSPInitialized; + + /* Our service provider */ + HMODULE hServiceProvider; + + /* Our DP lobby provider */ + HMODULE hDPLobbyProvider; + + enum SPSTATE connectionInitialized; + + /* Expected messages queue */ + DPQ_HEAD( tagDP_MSG_REPLY_STRUCT_LIST ) replysExpected; +} DirectPlay2Data; + +typedef struct tagDirectPlay3Data +{ + BOOL dummy; +} DirectPlay3Data; +typedef struct tagDirectPlay4Data +{ + BOOL dummy; +} DirectPlay4Data; + +#define DP_IMPL_FIELDS \ + LONG ulInterfaceRef; \ + DirectPlayIUnknownData* unk; \ + DirectPlay2Data* dp2; \ + DirectPlay3Data* dp3; \ + DirectPlay4Data* dp4; + +struct IDirectPlay2Impl +{ + const IDirectPlay2Vtbl *lpVtbl; + DP_IMPL_FIELDS +}; + +struct IDirectPlay3Impl +{ + const IDirectPlay3Vtbl *lpVtbl; + DP_IMPL_FIELDS +}; + +struct IDirectPlay4Impl +{ + const IDirectPlay4Vtbl *lpVtbl; + DP_IMPL_FIELDS +}; + +HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody, + DWORD dwMessageBodySize, LPCVOID lpMessageHeader, + WORD wCommandId, WORD wVersion, + LPVOID* lplpReply, LPDWORD lpdwMsgSize ); + +/* DP SP external interfaces into DirectPlay */ +extern HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP, DPID idPlayer, LPVOID* lplpData ); +extern HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP, DPID idPlayer, LPVOID lpData ); + +/* DP external interfaces to call into DPSP interface */ +extern LPVOID DPSP_CreateSPPlayerData(void); + +#endif /* __WINE_DPLAY_GLOBAL_INCLUDED */ diff --git a/reactos/lib/dplayx/dplaysp.c b/reactos/lib/dplayx/dplaysp.c new file mode 100644 index 00000000000..63421d543e9 --- /dev/null +++ b/reactos/lib/dplayx/dplaysp.c @@ -0,0 +1,955 @@ +/* This contains the implementation of the interface Service + * Providers require to communicate with Direct Play + * + * Copyright 2000 Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "winerror.h" +#include "wine/debug.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 */ + +WINE_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 +{ + LONG 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 */ + +} DirectPlaySPData; + +#define DPSP_IMPL_FIELDS \ + LONG ulInterfaceRef; \ + DirectPlaySPIUnknownData* unk; \ + DirectPlaySPData* sp; + +struct IDirectPlaySPImpl +{ + const IDirectPlaySPVtbl *lpVtbl; + DPSP_IMPL_FIELDS +}; + +/* Forward declaration of virtual tables */ +static const IDirectPlaySPVtbl directPlaySPVT; + +/* This structure is passed to the DP object for safe keeping */ +typedef struct tagDP_SPPLAYERDATA +{ + LPVOID lpPlayerLocalData; + DWORD dwPlayerLocalDataSize; + + LPVOID lpPlayerRemoteData; + DWORD dwPlayerRemoteDataSize; +} DP_SPPLAYERDATA, *LPDP_SPPLAYERDATA; + +/* 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 ) ) + { + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)*ppvObj; + This->lpVtbl = &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 ) +{ + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)lpSP; + + This->unk = 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 ) +{ + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)lpSP; + + DeleteCriticalSection( &This->unk->DPSP_lock ); + HeapFree( GetProcessHeap(), 0, This->unk ); + + return TRUE; +} + + +static BOOL DPSP_CreateDirectPlaySP( LPVOID lpSP, IDirectPlay2Impl* dp ) +{ + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)lpSP; + + This->sp = 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. + * + * FIXME: This is a kludge to get around a problem where a queryinterface + * is used to get a new interface and then is closed. We will then + * reference garbage. However, with this we will never deallocate + * the interface we store. The correct fix is to require all + * DP internal interfaces to use the This->dp2 interface which + * should be changed to This->dp + */ + IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp ); + + return TRUE; +} + +static BOOL DPSP_DestroyDirectPlaySP( LPVOID lpSP ) +{ + IDirectPlaySPImpl *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 ) +{ + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface; + TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj ); + + *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *This ) ); + + if( *ppvObj == NULL ) + { + return DPERR_OUTOFMEMORY; + } + + CopyMemory( *ppvObj, This, sizeof( *This ) ); + (*(IDirectPlaySPImpl**)ppvObj)->ulInterfaceRef = 0; + + if( IsEqualGUID( &IID_IDirectPlaySP, riid ) ) + { + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)*ppvObj; + This->lpVtbl = &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; + IDirectPlaySPImpl *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; + IDirectPlaySPImpl *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 +) +{ + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface; + + /* Should be able to call the comctl32 undocumented MRU routines. + I suspect that the interface works appropriately */ + 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 +) +{ + IDirectPlaySPImpl *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 +) +{ + IDirectPlaySPImpl *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 +) +{ + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface; + + /* Should be able to call the comctl32 undocumented MRU routines. + I suspect that the interface works appropriately */ + 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 +) +{ + IDirectPlaySPImpl *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 +) +{ + HRESULT hr; + LPDP_SPPLAYERDATA lpPlayerData; + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface; + + TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx)\n", + This, idPlayer, lplpData, lpdwDataSize, dwFlags ); + + hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerData ); + + if( FAILED(hr) ) + { + TRACE( "Couldn't get player data: %s\n", DPLAYX_HresultToString(hr) ); + return DPERR_INVALIDPLAYER; + } + + /* What to do in the case where there is nothing set yet? */ + if( dwFlags == DPSET_LOCAL ) + { + HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerLocalData ); + *lplpData = lpPlayerData->lpPlayerLocalData; + *lpdwDataSize = lpPlayerData->dwPlayerLocalDataSize; + } + else if( dwFlags == DPSET_REMOTE ) + { + HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerRemoteData ); + *lplpData = lpPlayerData->lpPlayerRemoteData; + *lpdwDataSize = lpPlayerData->dwPlayerRemoteDataSize; + } + + if( *lplpData == NULL ) + { + hr = DPERR_GENERIC; + } + + return hr; +} + +static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage +( LPDIRECTPLAYSP iface, + LPVOID lpMessageBody, + DWORD dwMessageBodySize, + LPVOID lpMessageHeader +) +{ + LPDPMSG_SENDENVELOPE lpMsg = (LPDPMSG_SENDENVELOPE)lpMessageBody; + HRESULT hr = DPERR_GENERIC; + WORD wCommandId; + WORD wVersion; + DPSP_REPLYDATA data; + + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface; + + FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n", + This, lpMessageBody, dwMessageBodySize, lpMessageHeader ); + + wCommandId = lpMsg->wCommandId; + wVersion = lpMsg->wVersion; + + TRACE( "Incoming message has envelope of 0x%08lx, %u, %u\n", + lpMsg->dwMagic, wCommandId, wVersion ); + + if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG ) + { + ERR( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic ); + return DPERR_GENERIC; + } + +#if 0 + { + const LPDWORD lpcHeader = (LPDWORD)lpMessageHeader; + + TRACE( "lpMessageHeader = [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx]\n", + lpcHeader[0], lpcHeader[1], lpcHeader[2], lpcHeader[3], lpcHeader[4] ); + } +#endif + + /* Pass everything else to Direct Play */ + data.lpMessage = NULL; + data.dwMessageSize = 0; + + /* Pass this message to the dplay interface to handle */ + hr = DP_HandleMessage( This->sp->dplay, lpMessageBody, dwMessageBodySize, + lpMessageHeader, wCommandId, wVersion, + &data.lpMessage, &data.dwMessageSize ); + + if( FAILED(hr) ) + { + ERR( "Command processing failed %s\n", DPLAYX_HresultToString(hr) ); + } + + /* Do we want a reply? */ + if( data.lpMessage != NULL ) + { + data.lpSPMessageHeader = lpMessageHeader; + data.idNameServer = 0; + data.lpISP = iface; + + hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data ); + + if( FAILED(hr) ) + { + ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr) ); + } + } + + return hr; + +#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: Who needs to delete the message when done? */ + 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 receive event was registered for this player, invoke it */ + if( hReceiveEvent ) + { + SetEvent( hReceiveEvent ); + } +#endif +} + +static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData +( LPDIRECTPLAYSP iface, + DPID idPlayer, + LPVOID lpData, + DWORD dwDataSize, + DWORD dwFlags +) +{ + HRESULT hr; + LPDP_SPPLAYERDATA lpPlayerEntry; + LPVOID lpPlayerData; + + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface; + +/* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */ + TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx)\n", + This, idPlayer, lpData, dwDataSize, dwFlags ); + + hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerEntry ); + if( FAILED(hr) ) + { + /* Player must not exist */ + return DPERR_INVALIDPLAYER; + } + + lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize ); + CopyMemory( lpPlayerData, lpData, dwDataSize ); + + if( dwFlags == DPSET_LOCAL ) + { + lpPlayerEntry->lpPlayerLocalData = lpPlayerData; + lpPlayerEntry->dwPlayerLocalDataSize = dwDataSize; + } + else if( dwFlags == DPSET_REMOTE ) + { + lpPlayerEntry->lpPlayerRemoteData = lpPlayerData; + lpPlayerEntry->dwPlayerRemoteDataSize = dwDataSize; + } + + hr = DP_SetSPPlayerData( This->sp->dplay, idPlayer, lpPlayerEntry ); + + return hr; +} + +static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress +( LPDIRECTPLAYSP iface, + LPCDPCOMPOUNDADDRESSELEMENT lpElements, + DWORD dwElementCount, + LPVOID lpAddress, + LPDWORD lpdwAddressSize +) +{ + IDirectPlaySPImpl *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 +) +{ + HRESULT hr = DP_OK; + IDirectPlaySPImpl *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 != DPSET_REMOTE ) + { + 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 != DPSET_REMOTE ) + { + TRACE( "Undocumented dwFlags 0x%08lx used\n", dwFlags ); + } +#endif + + /* FIXME: What to do in the case where this isn't initialized yet? */ + + /* Yes, we're supposed to return a pointer to the memory we have stored! */ + if( dwFlags == DPSET_REMOTE ) + { + *lpdwDataSize = This->sp->dwSpRemoteDataSize; + *lplpData = This->sp->lpSpRemoteData; + + if( This->sp->lpSpRemoteData == NULL ) + { + hr = DPERR_GENERIC; + } + } + else if( dwFlags == DPSET_LOCAL ) + { + *lpdwDataSize = This->sp->dwSpLocalDataSize; + *lplpData = This->sp->lpSpLocalData; + + if( This->sp->lpSpLocalData == NULL ) + { + hr = DPERR_GENERIC; + } + } + + return hr; +} + +static HRESULT WINAPI IDirectPlaySPImpl_SetSPData +( LPDIRECTPLAYSP iface, + LPVOID lpData, + DWORD dwDataSize, + DWORD dwFlags +) +{ + LPVOID lpSpData; + + IDirectPlaySPImpl *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 != DPSET_REMOTE ) + { + 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 != DPSET_REMOTE ) + { + TRACE( "Undocumented dwFlags 0x%08lx used\n", dwFlags ); + } +#endif + + 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 ) + { + HeapFree( GetProcessHeap(), 0, This->sp->lpSpRemoteData ); + This->sp->dwSpRemoteDataSize = dwDataSize; + This->sp->lpSpRemoteData = lpSpData; + } + else if ( dwFlags == DPSET_LOCAL ) + { + 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 +) +{ + IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface; + + FIXME( "(%p)->(%p,0x%08lx): stub\n", + This, unknownA, unknownB ); +} + +static const IDirectPlaySPVtbl directPlaySPVT = +{ + + 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 +}; + + +/* DP external interfaces to call into DPSP interface */ + +/* Allocate the structure */ +extern LPVOID DPSP_CreateSPPlayerData(void) +{ + TRACE( "Creating SPPlayer data struct\n" ); + return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( DP_SPPLAYERDATA ) ); +} diff --git a/reactos/lib/dplayx/dplaysp.h b/reactos/lib/dplayx/dplaysp.h new file mode 100644 index 00000000000..c12d0b47599 --- /dev/null +++ b/reactos/lib/dplayx/dplaysp.h @@ -0,0 +1,366 @@ +/* + * Copyright 2000 Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_DIRECT_PLAY_SP_H +#define __WINE_DIRECT_PLAY_SP_H + +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.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 *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 INTERFACE IDirectPlaySP +DECLARE_INTERFACE_(IDirectPlaySP,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirectPlaySP methods ***/ + STDMETHOD(AddMRUEntry)(THIS_ LPCWSTR lpSection, LPCWSTR lpKey, LPCVOID lpData, DWORD dwDataSize, DWORD dwMaxEntries ) PURE; + STDMETHOD(CreateAddress)(THIS_ REFGUID guidSP, REFGUID guidDataType, LPCVOID lpData, DWORD dwDataSize, LPVOID lpAddress,LPDWORD lpdwAddressSize) PURE; + STDMETHOD(EnumAddress)(THIS_ LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, DWORD dwAddressSize, LPVOID lpContext ) PURE; + STDMETHOD(EnumMRUEntries)(THIS_ LPCWSTR lpSection, LPCWSTR lpKey, LPENUMMRUCALLBACK lpEnumMRUCallback, LPVOID lpContext ) PURE; + STDMETHOD(GetPlayerFlags)(THIS_ DPID idPlayer, LPDWORD lpdwPlayerFlags ) PURE; + STDMETHOD(GetSPPlayerData)(THIS_ DPID idPlayer, LPVOID *lplpData, LPDWORD lpdwDataSize, DWORD dwFlags ) PURE; + STDMETHOD(HandleMessage)(THIS_ LPVOID lpMessageBody, DWORD dwMessageBodySize, LPVOID lpMessageHeader ) PURE; + STDMETHOD(SetSPPlayerData)(THIS_ DPID idPlayer, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags ) PURE; + STDMETHOD(CreateCompoundAddress)(THIS_ LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount, LPVOID lpAddress, LPDWORD lpdwAddressSize ) PURE; + STDMETHOD(GetSPData)(THIS_ LPVOID *lplpData, LPDWORD dwDataSize, DWORD dwFlags ) PURE; + STDMETHOD(SetSPData)(THIS_ LPVOID lpData, DWORD dwDataSize, DWORD dwFlags ) PURE; + STDMETHOD_(VOID,SendComplete)(THIS_ LPVOID , DWORD ) PURE; +}; +#undef INTERFACE + + +/* NOTE: The microsoft provided header file doesn't have these access + * functions + */ +#if !defined (__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirectPlaySP_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectPlaySP_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectPlaySP_Release(p) (p)->lpVtbl->Release(p) +/*** IDirectPlaySP methods ***/ +#define IDirectPlaySP_AddMRUEntry(p,a,b,c,d,e) (p)->lpVtbl->AddMRUEntry(p,a,b,c,d,e) +#define IDirectPlaySP_CreateAddress(p,a,b,c,d,e,f) (p)->lpVtbl->CreateAddress(p,a,b,c,d,e,f) +#define IDirectPlaySP_EnumAddress(p,a,b,c,d) (p)->lpVtbl->EnumAddress(p,a,b,c,d) +#define IDirectPlaySP_EnumMRUEntries(p,a,b,c,d) (p)->lpVtbl->EnumMRUEntries(p,a,b,c,d) +#define IDirectPlaySP_GetPlayerFlags(p,a,b) (p)->lpVtbl->GetPlayerFlags(p,a,b) +#define IDirectPlaySP_GetSPPlayerData(p,a,b,c,d) (p)->lpVtbl->GetSPPlayerData(p,a,b,c,d) +#define IDirectPlaySP_HandleMessage(p,a,b,c) (p)->lpVtbl->HandleMessage(p,a,b,c) +#define IDirectPlaySP_SetSPPlayerData(p,a,b,c,d) (p)->lpVtbl->SetSPPlayerData(p,a,b,c,d) +#define IDirectPlaySP_CreateCompoundAddress(p,a,b,c,d) (p)->lpVtbl->CreateCompoundAddress(p,a,b,c,d) +#define IDirectPlaySP_GetSPData(p,a,b,c) (p)->lpVtbl->GetSPData(p,a,b,c) +#define IDirectPlaySP_SetSPData(p,a,b,c) (p)->lpVtbl->SetSPData(p,a,b,c) +#define IDirectPlaySP_SendComplete(p,a,b) (p)->lpVtbl->SendComplete(p,a,b) +#endif + +/* 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/reactos/lib/dplayx/dplayx.spec b/reactos/lib/dplayx/dplayx.spec new file mode 100644 index 00000000000..7a17b03fe52 --- /dev/null +++ b/reactos/lib/dplayx/dplayx.spec @@ -0,0 +1,12 @@ + 1 stdcall DirectPlayCreate(ptr ptr ptr) + 2 stdcall DirectPlayEnumerateA(ptr ptr) + 3 stdcall DirectPlayEnumerateW(ptr ptr) + 4 stdcall DirectPlayLobbyCreateA(ptr ptr ptr ptr long) + 5 stdcall DirectPlayLobbyCreateW(ptr ptr ptr ptr long) + 6 extern gdwDPlaySPRefCount + 9 stdcall DirectPlayEnumerate(ptr ptr) DirectPlayEnumerateA + +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetClassObject(ptr ptr ptr) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() diff --git a/reactos/lib/dplayx/dplayx.xml b/reactos/lib/dplayx/dplayx.xml new file mode 100644 index 00000000000..2647d41bcb4 --- /dev/null +++ b/reactos/lib/dplayx/dplayx.xml @@ -0,0 +1,33 @@ + + + . + include/wine + + + + + 0x600 + 0x501 + 0x501 + wine + uuid + ntdll + kernel32 + user32 + advapi32 + ole32 + winmm + dxguid + version.rc + dpclassfactory.c + dplay.c + dplaysp.c + dplayx_global.c + dplayx_main.c + dplayx_messages.c + dplobby.c + lobbysp.c + name_server.c + regsvr.c + dplayx.spec + diff --git a/reactos/lib/dplayx/dplayx_global.c b/reactos/lib/dplayx/dplayx_global.c new file mode 100644 index 00000000000..0650c5280d9 --- /dev/null +++ b/reactos/lib/dplayx/dplayx_global.c @@ -0,0 +1,1354 @@ +/* dplayx.dll global data implementation. + * + * Copyright 1999,2000 - Peter Hunnisett + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * NOTES: + * o Implementation of all things which are associated with dplay on + * the computer - ie shared resources and such. Methods in this + * compilation unit should not call anything out side this unit + * excepting base windows services and an interface to start the + * messaging thread. + * o Methods that begin with DPLAYX_ are used for dealing with + * dplayx.dll data which is accessible from all processes. + * + */ + +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "wine/debug.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/unicode.h" + +#include "wingdi.h" +#include "winuser.h" + +#include "dplayx_global.h" +#include "dplayx_messages.h" /* For CreateMessageReceptionThread only */ + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +/* FIXME: Need to do all that fun other dll referencing type of stuff */ + +/* Static data for all processes */ +static LPCSTR lpszDplayxSemaName = "WINE_DPLAYX_SM"; +static HANDLE hDplayxSema; + +static LPCSTR lpszDplayxFileMapping = "WINE_DPLAYX_FM"; +static HANDLE hDplayxSharedMem; + +static LPVOID lpSharedStaticData = NULL; + + +#define DPLAYX_AquireSemaphore() TRACE( "Waiting for DPLAYX semaphore\n" ); \ + WaitForSingleObject( hDplayxSema, INFINITE );\ + TRACE( "Through wait\n" ) + +#define DPLAYX_ReleaseSemaphore() ReleaseSemaphore( hDplayxSema, 1, NULL ); \ + TRACE( "DPLAYX Semaphore released\n" ) /* FIXME: Is this correct? */ + + +/* HACK for simple global data right now */ +#define dwStaticSharedSize (128 * 1024) /* 128 KBytes */ +#define dwDynamicSharedSize (512 * 1024) /* 512 KBytes */ +#define dwTotalSharedSize ( dwStaticSharedSize + dwDynamicSharedSize ) + + +/* FIXME: Is there no easier way? */ + +/* Pretend the entire dynamic area is carved up into 512 byte blocks. + * Each block has 4 bytes which are 0 unless used */ +#define dwBlockSize 512 +#define dwMaxBlock (dwDynamicSharedSize/dwBlockSize) + +typedef struct +{ + DWORD used; + DWORD data[dwBlockSize-sizeof(DWORD)]; +} DPLAYX_MEM_SLICE; + +static DPLAYX_MEM_SLICE* lpMemArea; + +void DPLAYX_PrivHeapFree( LPVOID addr ); +void DPLAYX_PrivHeapFree( LPVOID addr ) +{ + LPVOID lpAddrStart; + DWORD dwBlockUsed; + + /* Handle getting passed a NULL */ + if( addr == NULL ) + { + return; + } + + lpAddrStart = (char*)addr - sizeof(DWORD); /* Find block header */ + dwBlockUsed = ((BYTE*)lpAddrStart - (BYTE*)lpMemArea)/dwBlockSize; + + lpMemArea[ dwBlockUsed ].used = 0; +} + +/* FIXME: This should be static, but is being used for a hack right now */ +LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size ); +LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size ) +{ + LPVOID lpvArea = NULL; + UINT uBlockUsed; + + if( size > (dwBlockSize - sizeof(DWORD)) ) + { + FIXME( "Size exceeded. Request of 0x%08lx\n", size ); + size = dwBlockSize - sizeof(DWORD); + } + + /* Find blank area */ + uBlockUsed = 0; + while( ( lpMemArea[ uBlockUsed ].used != 0 ) && ( uBlockUsed <= dwMaxBlock ) ) { uBlockUsed++; } + + if( uBlockUsed <= dwMaxBlock ) + { + /* Set the area used */ + lpMemArea[ uBlockUsed ].used = 1; + lpvArea = &(lpMemArea[ uBlockUsed ].data); + } + else + { + ERR( "No free block found\n" ); + return NULL; + } + + if( flags & HEAP_ZERO_MEMORY ) + { + ZeroMemory( lpvArea, size ); + } + + return lpvArea; +} + +LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str ); +LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str ) +{ + LPSTR p = DPLAYX_PrivHeapAlloc( flags, strlen(str) + 1 ); + if(p) { + strcpy( p, str ); + } + return p; +} + +LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str ); +LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str ) +{ + INT len = strlenW(str) + 1; + LPWSTR p = DPLAYX_PrivHeapAlloc( flags, len * sizeof(WCHAR) ); + if(p) { + strcpyW( p, str ); + } + return p; +} + + +enum { numSupportedLobbies = 32, numSupportedSessions = 32 }; +typedef struct tagDPLAYX_LOBBYDATA +{ + /* Points to lpConn + block of contiguous extra memory for dynamic parts + * of the struct directly following + */ + LPDPLCONNECTION lpConn; + + /* Information for dplobby interfaces */ + DWORD dwAppID; + DWORD dwAppLaunchedFromID; + + /* Should this lobby app send messages to creator at important life + * stages + */ + HANDLE hInformOnAppStart; + HANDLE hInformOnAppDeath; + HANDLE hInformOnSettingRead; + + /* Sundries */ + BOOL bWaitForConnectionSettings; + DWORD dwLobbyMsgThreadId; + + +} DPLAYX_LOBBYDATA, *LPDPLAYX_LOBBYDATA; + +static DPLAYX_LOBBYDATA* lobbyData = NULL; +/* static DPLAYX_LOBBYDATA lobbyData[ numSupportedLobbies ]; */ + +static DPSESSIONDESC2* sessionData = NULL; +/* static DPSESSIONDESC2* sessionData[ numSupportedSessions ]; */ + +/* Function prototypes */ +DWORD DPLAYX_SizeOfLobbyDataA( LPDPLCONNECTION lpDplData ); +DWORD DPLAYX_SizeOfLobbyDataW( LPDPLCONNECTION lpDplData ); +void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src ); +void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src ); +BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppId, LPDPLAYX_LOBBYDATA* dplData ); +void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData ); +BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2 lpSessionDest, + LPCDPSESSIONDESC2 lpSessionSrc ); + + + +/*************************************************************************** + * Called to initialize the global data. This will only be used on the + * loading of the dll + ***************************************************************************/ +BOOL DPLAYX_ConstructData(void) +{ + SECURITY_ATTRIBUTES s_attrib; + BOOL bInitializeSharedMemory = FALSE; + LPVOID lpDesiredMemoryMapStart = (LPVOID)0x50000000; + HANDLE hInformOnStart; + + TRACE( "DPLAYX dll loaded - construct called\n" ); + + /* Create a semaphore to block access to DPLAYX global data structs */ + + s_attrib.bInheritHandle = TRUE; + s_attrib.lpSecurityDescriptor = NULL; + s_attrib.nLength = sizeof(s_attrib); + + hDplayxSema = CreateSemaphoreA( &s_attrib, 1, 1, lpszDplayxSemaName ); + + /* First instance creates the semaphore. Others just use it */ + if( GetLastError() == ERROR_SUCCESS ) + { + TRACE( "Semaphore %p created\n", hDplayxSema ); + + /* The semaphore creator will also build the shared memory */ + bInitializeSharedMemory = TRUE; + } + else if ( GetLastError() == ERROR_ALREADY_EXISTS ) + { + TRACE( "Found semaphore handle %p\n", hDplayxSema ); + } + else + { + ERR( ": semaphore error %ld\n", GetLastError() ); + return FALSE; + } + + SetLastError( ERROR_SUCCESS ); + + DPLAYX_AquireSemaphore(); + + hDplayxSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE, + &s_attrib, + PAGE_READWRITE | SEC_COMMIT, + 0, + dwTotalSharedSize, + lpszDplayxFileMapping ); + + if( GetLastError() == ERROR_SUCCESS ) + { + TRACE( "File mapped %p created\n", hDplayxSharedMem ); + } + else if ( GetLastError() == ERROR_ALREADY_EXISTS ) + { + TRACE( "Found FileMapping handle %p\n", hDplayxSharedMem ); + } + else + { + ERR( ": unable to create shared memory (%ld)\n", GetLastError() ); + return FALSE; + } + + lpSharedStaticData = MapViewOfFileEx( hDplayxSharedMem, + FILE_MAP_WRITE, + 0, 0, 0, lpDesiredMemoryMapStart ); + + if( lpSharedStaticData == NULL ) + { + ERR( ": unable to map static data into process memory space (%ld)\n", + GetLastError() ); + return FALSE; + } + else + { + if( lpDesiredMemoryMapStart == lpSharedStaticData ) + { + TRACE( "File mapped to %p\n", lpSharedStaticData ); + } + else + { + /* Presently the shared data structures use pointers. If the + * files are no mapped into the same area, the pointers will no + * longer make any sense :( + * FIXME: In the future make the shared data structures have some + * sort of fixup to make them independent between data spaces. + * This will also require a rework of the session data stuff. + */ + ERR( "File mapped to %p (not %p). Expect failure\n", + lpSharedStaticData, lpDesiredMemoryMapStart ); + } + } + + /* Dynamic area starts just after the static area */ + lpMemArea = (LPVOID)((BYTE*)lpSharedStaticData + dwStaticSharedSize); + + /* FIXME: Crude hack */ + lobbyData = (DPLAYX_LOBBYDATA*)lpSharedStaticData; + sessionData = (DPSESSIONDESC2*)((BYTE*)lpSharedStaticData + (dwStaticSharedSize/2)); + + /* Initialize shared data segments. */ + if( bInitializeSharedMemory ) + { + UINT i; + + TRACE( "Initializing shared memory\n" ); + + /* Set all lobbies to be "empty" */ + for( i=0; i < numSupportedLobbies; i++ ) + { + DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] ); + } + + /* Set all sessions to be "empty" */ + for( i=0; i < numSupportedSessions; i++ ) + { + sessionData[i].dwSize = 0; + } + + /* Zero out the dynmaic area */ + ZeroMemory( lpMemArea, dwDynamicSharedSize ); + + /* Just for fun sync the whole data area */ + FlushViewOfFile( lpSharedStaticData, dwTotalSharedSize ); + } + + 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 %p %s\n", + hInformOnStart, bSuccess ? "succeed" : "failed" ); + + /* Close out handle */ + DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, TRUE ); + } + + return TRUE; +} + +/*************************************************************************** + * Called to destroy all global data. This will only be used on the + * unloading of the dll + ***************************************************************************/ +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 %p %s\n", + hInformOnDeath, bSuccess ? "succeed" : "failed" ); + + /* Close out handle */ + DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, TRUE ); + } + + /* DO CLEAN UP (LAST) */ + + /* Delete the semaphore */ + CloseHandle( hDplayxSema ); + + /* Delete shared memory file mapping */ + UnmapViewOfFile( lpSharedStaticData ); + CloseHandle( hDplayxSharedMem ); + + return FALSE; +} + + +void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData ) +{ + ZeroMemory( lpData, sizeof( *lpData ) ); +} + +/* NOTE: This must be called with the semaphore aquired. + * TRUE/FALSE with a pointer to it's data returned. Pointer data is + * is only valid if TRUE is returned. + */ +BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppID, LPDPLAYX_LOBBYDATA* lplpDplData ) +{ + UINT i; + + *lplpDplData = NULL; + + if( dwAppID == 0 ) + { + dwAppID = GetCurrentProcessId(); + TRACE( "Translated dwAppID == 0 into 0x%08lx\n", dwAppID ); + } + + for( i=0; i < numSupportedLobbies; i++ ) + { + if( lobbyData[ i ].dwAppID == dwAppID ) + { + /* This process is lobbied */ + TRACE( "Found 0x%08lx @ %u\n", dwAppID, i ); + *lplpDplData = &lobbyData[ i ]; + return TRUE; + } + } + + return FALSE; +} + +/* Reserve a spot for the new appliction. TRUE means success and FALSE failure. */ +BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID ) +{ + UINT i; + + /* 0 is the marker for unused application data slots */ + if( dwAppID == 0 ) + { + return FALSE; + } + + DPLAYX_AquireSemaphore(); + + /* Find an empty space in the list and insert the data */ + for( i=0; i < numSupportedLobbies; i++ ) + { + if( lobbyData[ i ].dwAppID == 0 ) + { + /* This process is now lobbied */ + TRACE( "Setting lobbyData[%u] for (0x%08lx,0x%08lx)\n", + i, dwAppID, GetCurrentProcessId() ); + + lobbyData[ i ].dwAppID = dwAppID; + lobbyData[ i ].dwAppLaunchedFromID = GetCurrentProcessId(); + + /* 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; + } + } + + ERR( "No empty lobbies\n" ); + + DPLAYX_ReleaseSemaphore(); + return FALSE; +} + +/* I'm not sure when I'm going to need this, but here it is */ +BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID ) +{ + UINT i; + + DPLAYX_AquireSemaphore(); + + /* Find an empty space in the list and insert the data */ + for( i=0; i < numSupportedLobbies; i++ ) + { + if( lobbyData[ i ].dwAppID == dwAppID ) + { + /* FIXME: Should free up anything unused. Tisk tisk :0 */ + /* Mark this entry unused */ + TRACE( "Marking lobbyData[%u] unused\n", i ); + DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] ); + + DPLAYX_ReleaseSemaphore(); + return TRUE; + } + } + + DPLAYX_ReleaseSemaphore(); + ERR( "Unable to find global entry for application\n" ); + 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 ) +{ + LPDPLAYX_LOBBYDATA lpDplData; + DWORD dwRequiredDataSize = 0; + HANDLE hInformOnSettingRead; + + DPLAYX_AquireSemaphore(); + + if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) ) + { + DPLAYX_ReleaseSemaphore(); + + TRACE( "Application 0x%08lx is not lobbied\n", dwAppID ); + return DPERR_NOTLOBBIED; + } + + dwRequiredDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn ); + + /* Do they want to know the required buffer size or is the provided buffer + * big enough? + */ + if ( ( lpData == NULL ) || + ( *lpdwDataSize < dwRequiredDataSize ) + ) + { + DPLAYX_ReleaseSemaphore(); + + *lpdwDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn ); + + return DPERR_BUFFERTOOSMALL; + } + + 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 %p %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; + + CopyMemory( dest, src, sizeof( DPLCONNECTION ) ); + + lpStartOfFreeSpace = ((BYTE*)dest) + sizeof( DPLCONNECTION ); + + /* Copy the LPDPSESSIONDESC2 structure if it exists */ + if( src->lpSessionDesc ) + { + dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 ); + CopyMemory( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) ); + + /* Session names may or may not exist */ + if( src->lpSessionDesc->lpszSessionNameA ) + { + strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->lpszSessionNameA ); + dest->lpSessionDesc->lpszSessionNameA = (LPSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += + strlen( (LPSTR)dest->lpSessionDesc->lpszSessionNameA ) + 1; + } + + if( src->lpSessionDesc->lpszPasswordA ) + { + strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->lpszPasswordA ); + dest->lpSessionDesc->lpszPasswordA = (LPSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += + strlen( (LPSTR)dest->lpSessionDesc->lpszPasswordA ) + 1; + } + } + + /* DPNAME structure is optional */ + if( src->lpPlayerName ) + { + dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof( DPNAME ); + CopyMemory( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) ); + + if( src->lpPlayerName->lpszShortNameA ) + { + strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->lpszShortNameA ); + dest->lpPlayerName->lpszShortNameA = (LPSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += + strlen( (LPSTR)dest->lpPlayerName->lpszShortNameA ) + 1; + } + + if( src->lpPlayerName->lpszLongNameA ) + { + strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->lpszLongNameA ); + dest->lpPlayerName->lpszLongNameA = (LPSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += + strlen( (LPSTR)dest->lpPlayerName->lpszLongName ) + 1 ; + } + + } + + /* Copy address if it exists */ + if( src->lpAddress ) + { + dest->lpAddress = (LPVOID)lpStartOfFreeSpace; + CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize ); + /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */ + } +} + +HRESULT DPLAYX_GetConnectionSettingsW +( DWORD dwAppID, + LPVOID lpData, + LPDWORD lpdwDataSize ) +{ + LPDPLAYX_LOBBYDATA lpDplData; + DWORD dwRequiredDataSize = 0; + HANDLE hInformOnSettingRead; + + DPLAYX_AquireSemaphore(); + + if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) ) + { + DPLAYX_ReleaseSemaphore(); + return DPERR_NOTLOBBIED; + } + + dwRequiredDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn ); + + /* Do they want to know the required buffer size or is the provided buffer + * big enough? + */ + if ( ( lpData == NULL ) || + ( *lpdwDataSize < dwRequiredDataSize ) + ) + { + DPLAYX_ReleaseSemaphore(); + + *lpdwDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn ); + + return DPERR_BUFFERTOOSMALL; + } + + 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 %p %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_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src ) +{ + BYTE* lpStartOfFreeSpace; + + CopyMemory( dest, src, sizeof( DPLCONNECTION ) ); + + lpStartOfFreeSpace = ( (BYTE*)dest) + sizeof( DPLCONNECTION ); + + /* Copy the LPDPSESSIONDESC2 structure if it exists */ + if( src->lpSessionDesc ) + { + dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 ); + CopyMemory( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) ); + + /* Session names may or may not exist */ + if( src->lpSessionDesc->lpszSessionName ) + { + strcpyW( (LPWSTR)lpStartOfFreeSpace, dest->lpSessionDesc->lpszSessionName ); + src->lpSessionDesc->lpszSessionName = (LPWSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof(WCHAR) * + ( strlenW( (LPWSTR)dest->lpSessionDesc->lpszSessionName ) + 1 ); + } + + if( src->lpSessionDesc->lpszPassword ) + { + strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpSessionDesc->lpszPassword ); + dest->lpSessionDesc->lpszPassword = (LPWSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof(WCHAR) * + ( strlenW( (LPWSTR)dest->lpSessionDesc->lpszPassword ) + 1 ); + } + } + + /* DPNAME structure is optional */ + if( src->lpPlayerName ) + { + dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof( DPNAME ); + CopyMemory( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) ); + + if( src->lpPlayerName->lpszShortName ) + { + strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->lpszShortName ); + dest->lpPlayerName->lpszShortName = (LPWSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof(WCHAR) * + ( strlenW( (LPWSTR)dest->lpPlayerName->lpszShortName ) + 1 ); + } + + if( src->lpPlayerName->lpszLongName ) + { + strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->lpszLongName ); + dest->lpPlayerName->lpszLongName = (LPWSTR)lpStartOfFreeSpace; + lpStartOfFreeSpace += sizeof(WCHAR) * + ( strlenW( (LPWSTR)dest->lpPlayerName->lpszLongName ) + 1 ); + } + + } + + /* Copy address if it exists */ + if( src->lpAddress ) + { + dest->lpAddress = (LPVOID)lpStartOfFreeSpace; + CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize ); + /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */ + } + +} + +/* Store the structure into the shared data structre. Ensure that allocs for + * variable length strings come from the shared data structure. + * FIXME: We need to free information as well + */ +HRESULT DPLAYX_SetConnectionSettingsA +( DWORD dwFlags, + DWORD dwAppID, + LPDPLCONNECTION lpConn ) +{ + LPDPLAYX_LOBBYDATA lpDplData; + + /* Parameter check */ + if( dwFlags || !lpConn ) + { + ERR("invalid parameters.\n"); + return DPERR_INVALIDPARAMS; + } + + /* Store information */ + if( lpConn->dwSize != sizeof(DPLCONNECTION) ) + { + ERR(": old/new DPLCONNECTION type? Size=%08lx vs. expected=%ul bytes\n", + lpConn->dwSize, sizeof( DPLCONNECTION ) ); + + return DPERR_INVALIDPARAMS; + } + + DPLAYX_AquireSemaphore(); + + if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) ) + { + DPLAYX_ReleaseSemaphore(); + + return DPERR_NOTLOBBIED; + } + + if( (!lpConn->lpSessionDesc ) || + ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) ) + ) + { + DPLAYX_ReleaseSemaphore(); + + ERR("DPSESSIONDESC passed in? Size=%lu vs. expected=%u bytes\n", + lpConn->lpSessionDesc->dwSize, sizeof( DPSESSIONDESC2 ) ); + + return DPERR_INVALIDPARAMS; + } + + /* Free the existing memory */ + DPLAYX_PrivHeapFree( lpDplData->lpConn ); + + lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, + DPLAYX_SizeOfLobbyDataA( lpConn ) ); + + DPLAYX_CopyConnStructA( lpDplData->lpConn, lpConn ); + + + DPLAYX_ReleaseSemaphore(); + + /* FIXME: Send a message - I think */ + + return DP_OK; +} + +/* Store the structure into the shared data structre. Ensure that allocs for + * variable length strings come from the shared data structure. + * FIXME: We need to free information as well + */ +HRESULT DPLAYX_SetConnectionSettingsW +( DWORD dwFlags, + DWORD dwAppID, + LPDPLCONNECTION lpConn ) +{ + LPDPLAYX_LOBBYDATA lpDplData; + + /* Parameter check */ + if( dwFlags || !lpConn ) + { + ERR("invalid parameters.\n"); + return DPERR_INVALIDPARAMS; + } + + /* Store information */ + if( lpConn->dwSize != sizeof(DPLCONNECTION) ) + { + ERR(": old/new DPLCONNECTION type? Size=%lu vs. expected=%u bytes\n", + lpConn->dwSize, sizeof( DPLCONNECTION ) ); + + return DPERR_INVALIDPARAMS; + } + + DPLAYX_AquireSemaphore(); + + if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) ) + { + DPLAYX_ReleaseSemaphore(); + + return DPERR_NOTLOBBIED; + } + + /* Free the existing memory */ + DPLAYX_PrivHeapFree( lpDplData->lpConn ); + + lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, + DPLAYX_SizeOfLobbyDataW( lpConn ) ); + + DPLAYX_CopyConnStructW( lpDplData->lpConn, lpConn ); + + + DPLAYX_ReleaseSemaphore(); + + /* FIXME: Send a message - I think */ + + return DP_OK; +} + +DWORD DPLAYX_SizeOfLobbyDataA( LPDPLCONNECTION lpConn ) +{ + DWORD dwTotalSize = sizeof( DPLCONNECTION ); + + /* Just a safety check */ + if( lpConn == NULL ) + { + ERR( "lpConn is NULL\n" ); + return 0; + } + + if( lpConn->lpSessionDesc != NULL ) + { + dwTotalSize += sizeof( DPSESSIONDESC2 ); + + if( lpConn->lpSessionDesc->lpszSessionNameA ) + { + dwTotalSize += strlen( lpConn->lpSessionDesc->lpszSessionNameA ) + 1; + } + + if( lpConn->lpSessionDesc->lpszPasswordA ) + { + dwTotalSize += strlen( lpConn->lpSessionDesc->lpszPasswordA ) + 1; + } + } + + if( lpConn->lpPlayerName != NULL ) + { + dwTotalSize += sizeof( DPNAME ); + + if( lpConn->lpPlayerName->lpszShortNameA ) + { + dwTotalSize += strlen( lpConn->lpPlayerName->lpszShortNameA ) + 1; + } + + if( lpConn->lpPlayerName->lpszLongNameA ) + { + dwTotalSize += strlen( lpConn->lpPlayerName->lpszLongNameA ) + 1; + } + + } + + dwTotalSize += lpConn->dwAddressSize; + + return dwTotalSize; +} + +DWORD DPLAYX_SizeOfLobbyDataW( LPDPLCONNECTION lpConn ) +{ + DWORD dwTotalSize = sizeof( DPLCONNECTION ); + + /* Just a safety check */ + if( lpConn == NULL ) + { + ERR( "lpConn is NULL\n" ); + return 0; + } + + if( lpConn->lpSessionDesc != NULL ) + { + dwTotalSize += sizeof( DPSESSIONDESC2 ); + + if( lpConn->lpSessionDesc->lpszSessionName ) + { + dwTotalSize += sizeof( WCHAR ) * + ( strlenW( lpConn->lpSessionDesc->lpszSessionName ) + 1 ); + } + + if( lpConn->lpSessionDesc->lpszPassword ) + { + dwTotalSize += sizeof( WCHAR ) * + ( strlenW( lpConn->lpSessionDesc->lpszPassword ) + 1 ); + } + } + + if( lpConn->lpPlayerName != NULL ) + { + dwTotalSize += sizeof( DPNAME ); + + if( lpConn->lpPlayerName->lpszShortName ) + { + dwTotalSize += sizeof( WCHAR ) * + ( strlenW( lpConn->lpPlayerName->lpszShortName ) + 1 ); + } + + if( lpConn->lpPlayerName->lpszLongName ) + { + dwTotalSize += sizeof( WCHAR ) * + ( strlenW( lpConn->lpPlayerName->lpszLongName ) + 1 ); + } + + } + + dwTotalSize += lpConn->dwAddressSize; + + return dwTotalSize; +} + + + +static LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateSessionDesc2A( LPCDPSESSIONDESC2 lpSessionSrc ) +{ + LPDPSESSIONDESC2 lpSessionDest = + HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpSessionSrc ) ); + DPLAYX_CopyIntoSessionDesc2A( lpSessionDest, lpSessionSrc ); + + return lpSessionDest; +} + +/* Copy an ANSI session desc structure to the given buffer */ +BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2 lpSessionDest, + LPCDPSESSIONDESC2 lpSessionSrc ) +{ + CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) ); + + if( lpSessionSrc->lpszSessionNameA ) + { + if ((lpSessionDest->lpszSessionNameA = HeapAlloc( GetProcessHeap(), 0, + strlen(lpSessionSrc->lpszSessionNameA)+1 ))) + strcpy( lpSessionDest->lpszSessionNameA, lpSessionSrc->lpszSessionNameA ); + } + if( lpSessionSrc->lpszPasswordA ) + { + if ((lpSessionDest->lpszPasswordA = HeapAlloc( GetProcessHeap(), 0, + strlen(lpSessionSrc->lpszPasswordA)+1 ))) + strcpy( lpSessionDest->lpszPasswordA, lpSessionSrc->lpszPasswordA ); + } + + return TRUE; +} + +/* Start the index at 0. index will be updated to equal that which should + be passed back into this function for the next element */ +LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateLocalSession( UINT* index ) +{ + for( ; (*index) < numSupportedSessions; (*index)++ ) + { + if( sessionData[(*index)].dwSize != 0 ) + { + return DPLAYX_CopyAndAllocateSessionDesc2A( &sessionData[(*index)++] ); + } + } + + /* No more sessions */ + return NULL; +} + +/* Start the index at 0. index will be updated to equal that which should + be passed back into this function for the next element */ +BOOL DPLAYX_CopyLocalSession( UINT* index, LPDPSESSIONDESC2 lpsd ) +{ + for( ; (*index) < numSupportedSessions; (*index)++ ) + { + if( sessionData[(*index)].dwSize != 0 ) + { + return DPLAYX_CopyIntoSessionDesc2A( lpsd, &sessionData[(*index)++] ); + } + } + + /* No more sessions */ + return FALSE; +} + +void DPLAYX_SetLocalSession( LPCDPSESSIONDESC2 lpsd ) +{ + UINT i; + + /* FIXME: Is this an error if it exists already? */ + + /* Crude/wrong implementation for now. Just always add to first empty spot */ + for( i=0; i < numSupportedSessions; i++ ) + { + /* Is this one empty? */ + if( sessionData[i].dwSize == 0 ) + { + DPLAYX_CopyIntoSessionDesc2A( &sessionData[i], lpsd ); + break; + } + } + +} + +BOOL DPLAYX_WaitForConnectionSettings( BOOL bWait ) +{ + LPDPLAYX_LOBBYDATA lpLobbyData; + + DPLAYX_AquireSemaphore(); + + if( !DPLAYX_IsAppIdLobbied( 0, &lpLobbyData ) ) + { + DPLAYX_ReleaseSemaphore(); + return FALSE; + } + + lpLobbyData->bWaitForConnectionSettings = bWait; + + DPLAYX_ReleaseSemaphore(); + + return TRUE; +} + +BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void) +{ + UINT i; + BOOL bFound = FALSE; + + DPLAYX_AquireSemaphore(); + + for( i=0; i < numSupportedLobbies; i++ ) + { + if( ( lobbyData[ i ].dwAppID != 0 ) && /* lobby initialized */ + ( lobbyData[ i ].bWaitForConnectionSettings ) /* Waiting */ + ) + { + bFound = TRUE; + break; + } + } + + DPLAYX_ReleaseSemaphore(); + + 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 + known. You will just get the last hr passed in. This can change + over time if this method is used a lot :) */ +LPCSTR DPLAYX_HresultToString(HRESULT hr) +{ + static char szTempStr[12]; + + switch (hr) + { + case DP_OK: + return "DP_OK"; + case DPERR_ALREADYINITIALIZED: + return "DPERR_ALREADYINITIALIZED"; + case DPERR_ACCESSDENIED: + return "DPERR_ACCESSDENIED"; + case DPERR_ACTIVEPLAYERS: + return "DPERR_ACTIVEPLAYERS"; + case DPERR_BUFFERTOOSMALL: + return "DPERR_BUFFERTOOSMALL"; + case DPERR_CANTADDPLAYER: + return "DPERR_CANTADDPLAYER"; + case DPERR_CANTCREATEGROUP: + return "DPERR_CANTCREATEGROUP"; + case DPERR_CANTCREATEPLAYER: + return "DPERR_CANTCREATEPLAYER"; + case DPERR_CANTCREATESESSION: + return "DPERR_CANTCREATESESSION"; + case DPERR_CAPSNOTAVAILABLEYET: + return "DPERR_CAPSNOTAVAILABLEYET"; + case DPERR_EXCEPTION: + return "DPERR_EXCEPTION"; + case DPERR_GENERIC: + return "DPERR_GENERIC"; + case DPERR_INVALIDFLAGS: + return "DPERR_INVALIDFLAGS"; + case DPERR_INVALIDOBJECT: + return "DPERR_INVALIDOBJECT"; + case DPERR_INVALIDPARAMS: + return "DPERR_INVALIDPARAMS"; + case DPERR_INVALIDPLAYER: + return "DPERR_INVALIDPLAYER"; + case DPERR_INVALIDGROUP: + return "DPERR_INVALIDGROUP"; + case DPERR_NOCAPS: + return "DPERR_NOCAPS"; + case DPERR_NOCONNECTION: + return "DPERR_NOCONNECTION"; + case DPERR_OUTOFMEMORY: + return "DPERR_OUTOFMEMORY"; + case DPERR_NOMESSAGES: + return "DPERR_NOMESSAGES"; + case DPERR_NONAMESERVERFOUND: + return "DPERR_NONAMESERVERFOUND"; + case DPERR_NOPLAYERS: + return "DPERR_NOPLAYERS"; + case DPERR_NOSESSIONS: + return "DPERR_NOSESSIONS"; + case DPERR_PENDING: + return "DPERR_PENDING"; + case DPERR_SENDTOOBIG: + return "DPERR_SENDTOOBIG"; + case DPERR_TIMEOUT: + return "DPERR_TIMEOUT"; + case DPERR_UNAVAILABLE: + return "DPERR_UNAVAILABLE"; + case DPERR_UNSUPPORTED: + return "DPERR_UNSUPPORTED"; + case DPERR_BUSY: + return "DPERR_BUSY"; + case DPERR_USERCANCEL: + return "DPERR_USERCANCEL"; + case DPERR_NOINTERFACE: + return "DPERR_NOINTERFACE"; + case DPERR_CANNOTCREATESERVER: + return "DPERR_CANNOTCREATESERVER"; + case DPERR_PLAYERLOST: + return "DPERR_PLAYERLOST"; + case DPERR_SESSIONLOST: + return "DPERR_SESSIONLOST"; + case DPERR_UNINITIALIZED: + return "DPERR_UNINITIALIZED"; + case DPERR_NONEWPLAYERS: + return "DPERR_NONEWPLAYERS"; + case DPERR_INVALIDPASSWORD: + return "DPERR_INVALIDPASSWORD"; + case DPERR_CONNECTING: + return "DPERR_CONNECTING"; + case DPERR_CONNECTIONLOST: + return "DPERR_CONNECTIONLOST"; + case DPERR_UNKNOWNMESSAGE: + return "DPERR_UNKNOWNMESSAGE"; + case DPERR_CANCELFAILED: + return "DPERR_CANCELFAILED"; + case DPERR_INVALIDPRIORITY: + return "DPERR_INVALIDPRIORITY"; + case DPERR_NOTHANDLED: + return "DPERR_NOTHANDLED"; + case DPERR_CANCELLED: + return "DPERR_CANCELLED"; + case DPERR_ABORTED: + return "DPERR_ABORTED"; + case DPERR_BUFFERTOOLARGE: + return "DPERR_BUFFERTOOLARGE"; + case DPERR_CANTCREATEPROCESS: + return "DPERR_CANTCREATEPROCESS"; + case DPERR_APPNOTSTARTED: + return "DPERR_APPNOTSTARTED"; + case DPERR_INVALIDINTERFACE: + return "DPERR_INVALIDINTERFACE"; + case DPERR_NOSERVICEPROVIDER: + return "DPERR_NOSERVICEPROVIDER"; + case DPERR_UNKNOWNAPPLICATION: + return "DPERR_UNKNOWNAPPLICATION"; + case DPERR_NOTLOBBIED: + return "DPERR_NOTLOBBIED"; + case DPERR_SERVICEPROVIDERLOADED: + return "DPERR_SERVICEPROVIDERLOADED"; + case DPERR_ALREADYREGISTERED: + return "DPERR_ALREADYREGISTERED"; + case DPERR_NOTREGISTERED: + return "DPERR_NOTREGISTERED"; + case DPERR_AUTHENTICATIONFAILED: + return "DPERR_AUTHENTICATIONFAILED"; + case DPERR_CANTLOADSSPI: + return "DPERR_CANTLOADSSPI"; + case DPERR_ENCRYPTIONFAILED: + return "DPERR_ENCRYPTIONFAILED"; + case DPERR_SIGNFAILED: + return "DPERR_SIGNFAILED"; + case DPERR_CANTLOADSECURITYPACKAGE: + return "DPERR_CANTLOADSECURITYPACKAGE"; + case DPERR_ENCRYPTIONNOTSUPPORTED: + return "DPERR_ENCRYPTIONNOTSUPPORTED"; + case DPERR_CANTLOADCAPI: + return "DPERR_CANTLOADCAPI"; + case DPERR_NOTLOGGEDIN: + return "DPERR_NOTLOGGEDIN"; + case DPERR_LOGONDENIED: + return "DPERR_LOGONDENIED"; + default: + /* For errors not in the list, return HRESULT as a string + This part is not thread safe */ + WARN( "Unknown error 0x%08lx\n", hr ); + wsprintfA( szTempStr, "0x%08lx", hr ); + return szTempStr; + } +} diff --git a/reactos/lib/dplayx/dplayx_global.h b/reactos/lib/dplayx/dplayx_global.h new file mode 100644 index 00000000000..9f518a850f0 --- /dev/null +++ b/reactos/lib/dplayx/dplayx_global.h @@ -0,0 +1,76 @@ +/* + * Copyright 1999, 2000 Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_DPLAYX_GLOBAL +#define __WINE_DPLAYX_GLOBAL + +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "dplay.h" + +BOOL DPLAYX_ConstructData(void); +BOOL DPLAYX_DestructData(void); + +HRESULT DPLAYX_GetConnectionSettingsA ( DWORD dwAppID, + LPVOID lpData, + LPDWORD lpdwDataSize ); +HRESULT DPLAYX_GetConnectionSettingsW ( DWORD dwAppID, + LPVOID lpData, + LPDWORD lpdwDataSize ); + +HRESULT DPLAYX_SetConnectionSettingsA ( DWORD dwFlags, + DWORD dwAppID, + LPDPLCONNECTION lpConn ); +HRESULT DPLAYX_SetConnectionSettingsW ( DWORD dwFlags, + DWORD dwAppID, + LPDPLCONNECTION lpConn ); + +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 ); + +#endif /* __WINE_DPLAYX_GLOBAL */ diff --git a/reactos/lib/dplayx/dplayx_main.c b/reactos/lib/dplayx/dplayx_main.c new file mode 100644 index 00000000000..1969d0d311d --- /dev/null +++ b/reactos/lib/dplayx/dplayx_main.c @@ -0,0 +1,111 @@ +/* + * DPLAYX.DLL LibMain + * + * Copyright 1999,2000 - Peter Hunnisett + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * o DPMSGCMD_ENUMSESSIONSREPLY & DPMSGCMD_ENUMSESSIONSREQUEST + * Have most fields understood, but not all. Everything seems to work. + * o DPMSGCMD_REQUESTNEWPLAYERID & DPMSGCMD_NEWPLAYERIDREPLY + * Barely work. This needs to be completed for sessions to start. + * o A small issue will be the fact that DirectX 6.1(ie. DirectPlay4) + * introduces a layer of functionality inside the DP objects which + * provide guaranteed protocol delivery. This is even if the native + * protocol, IPX or modem for instance, doesn't guarantee it. I'm going + * to leave this kind of implementation to as close to the end as + * possible. However, I will implement an abstraction layer, where + * possible, for this functionality. It will do nothing to start, but + * will require only the implementation of the guaranteness to give + * final implementation. + * + * TODO: + * - Implement mutual exclusion on object data for existing functions + * - Ensure that all dll stubs are present and the ordinals are correct + * - Addition of DirectX 7.0 functionality for direct play + * - Implement some WineLib test programs using sdk programs as a skeleton + * - Change RegEnumKeyEx enumeration pattern to allow error handling and to + * share registry implementation (or at least simplify). + * - Add in appropriate RegCloseKey calls for all the opening we're doing... + * - Fix all the buffer sizes for registry calls. They're off by one - + * but in a safe direction. + * - Fix race condition on interface destruction + * - Handles need to be correctly reference counted + * - Check if we need to deallocate any list objects when destroying + * a dplay interface + * - RunApplication process spawning needs to have correct syncronization. + * - Need to get inter lobby messages working. + * - Decypher dplay messages between applications and implement... + * - Need to implement lobby session spawning. + * - Improve footprint and realtime blocking by setting up a separate data share + * between lobby application and client since there can be multiple apps per + * client. Also get rid of offset dependency by making data offset independent + * somehow. + */ +#include + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" +#include "dplayx_global.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +/* This is a globally exported variable at ordinal 6 of DPLAYX.DLL */ +DWORD gdwDPlaySPRefCount = 0; /* FIXME: Should it be initialized here? */ + + +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) +{ + + TRACE( "(%p,%ld,%p)\n", hinstDLL, fdwReason, lpvReserved ); + + switch ( fdwReason ) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + /* First instance perform construction of global processor data */ + return DPLAYX_ConstructData(); + + case DLL_PROCESS_DETACH: + /* Last instance performs destruction of global processor data */ + return DPLAYX_DestructData(); + + default: + break; + + } + + return TRUE; +} + +/*********************************************************************** + * DllCanUnloadNow (DPLAYX.@) + */ +HRESULT WINAPI 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/reactos/lib/dplayx/dplayx_messages.c b/reactos/lib/dplayx/dplayx_messages.c new file mode 100644 index 00000000000..2b248aff24d --- /dev/null +++ b/reactos/lib/dplayx/dplayx_messages.c @@ -0,0 +1,511 @@ +/* DirectPlay & DirectPlayLobby messaging implementation + * + * Copyright 2000,2001 - Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * o Messaging interface required for both DirectPlay and DirectPlayLobby. + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" +#include "ntstatus.h" + +#include "dplayx_messages.h" +#include "dplay_global.h" +#include "dplayx_global.h" +#include "name_server.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +typedef struct tagMSGTHREADINFO +{ + HANDLE hStart; + HANDLE hDeath; + HANDLE hSettingRead; + HANDLE hNotifyEvent; +} MSGTHREADINFO, *LPMSGTHREADINFO; + +static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext ); +static LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA data, + DWORD dwWaitTime, WORD wReplyCommandId, + LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize ); + + +/* Create the message reception thread to allow the application to receive + * asynchronous message reception + */ +DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart, + HANDLE hDeath, HANDLE hConnRead ) +{ + DWORD dwMsgThreadId; + LPMSGTHREADINFO lpThreadInfo; + + lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) ); + if( lpThreadInfo == NULL ) + { + return 0; + } + + /* 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 DPL_MSG_ThreadMain( LPVOID 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 ( ;; ) + { + MSG lobbyMsg; + GetMessageW( &lobbyMsg, 0, 0, 0 ); + } + +end_of_thread: + TRACE( "Msg thread exiting!\n" ); + HeapFree( GetProcessHeap(), 0, lpThreadInfo ); + + return 0; +} + +/* DP messageing stuff */ +static HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This, + LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, + WORD wReplyCommandId ); +static LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, + LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize ); + + +static +HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This, + LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, WORD wReplyCommandId ) +{ + lpReplyStructList->replyExpected.hReceipt = CreateEventW( NULL, FALSE, FALSE, NULL ); + lpReplyStructList->replyExpected.wExpectedReply = wReplyCommandId; + lpReplyStructList->replyExpected.lpReplyMsg = NULL; + lpReplyStructList->replyExpected.dwMsgBodySize = 0; + + /* Insert into the message queue while locked */ + EnterCriticalSection( &This->unk->DP_lock ); + DPQ_INSERT( This->dp2->replysExpected, lpReplyStructList, replysExpected ); + LeaveCriticalSection( &This->unk->DP_lock ); + + return lpReplyStructList->replyExpected.hReceipt; +} + +static +LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, + LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize ) +{ + CloseHandle( lpReplyStructList->replyExpected.hReceipt ); + + *lplpReplyMsg = lpReplyStructList->replyExpected.lpReplyMsg; + *lpdwMsgBodySize = lpReplyStructList->replyExpected.dwMsgBodySize; + + return lpReplyStructList->replyExpected.lpReplyMsg; +} + +HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags, + LPDPID lpdpidAllocatedId ) +{ + LPVOID lpMsg; + LPDPMSG_REQUESTNEWPLAYERID lpMsgBody; + DWORD dwMsgSize; + HRESULT hr = DP_OK; + + dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody ); + + lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize ); + + lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg + + This->dp2->spData.dwSPHeaderSize ); + + /* Compose dplay message envelope */ + lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG; + lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID; + lpMsgBody->envelope.wVersion = DPMSGVER_DP6; + + /* Compose the body of the message */ + lpMsgBody->dwFlags = dwFlags; + + /* Send the message */ + { + DPSP_SENDDATA data; + + data.dwFlags = DPSEND_GUARANTEED; + data.idPlayerTo = 0; /* Name server */ + data.idPlayerFrom = 0; /* Sending from DP */ + data.lpMessage = lpMsg; + data.dwMessageSize = dwMsgSize; + data.bSystemMessage = TRUE; /* Allow reply to be sent */ + data.lpISP = This->dp2->spData.lpISP; + + TRACE( "Asking for player id w/ dwFlags 0x%08lx\n", + lpMsgBody->dwFlags ); + + DP_MSG_ExpectReply( This, &data, DPMSG_DEFAULT_WAIT_TIME, DPMSGCMD_NEWPLAYERIDREPLY, + &lpMsg, &dwMsgSize ); + } + + /* Need to examine the data and extract the new player id */ + if( !FAILED(hr) ) + { + LPCDPMSG_NEWPLAYERIDREPLY lpcReply; + + lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)lpMsg; + + *lpdpidAllocatedId = lpcReply->dpidNewPlayerId; + + TRACE( "Received reply for id = 0x%08lx\n", lpcReply->dpidNewPlayerId ); + + /* FIXME: I think that the rest of the message has something to do + * with remote data for the player that perhaps I need to setup. + * However, with the information that is passed, all that it could + * be used for is a standardized intialization value, which I'm + * guessing we can do without. Unless the message content is the same + * for several different messages? + */ + + HeapFree( GetProcessHeap(), 0, lpMsg ); + } + + return hr; +} + +HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer ) +{ + LPVOID lpMsg; + LPDPMSG_FORWARDADDPLAYER lpMsgBody; + DWORD dwMsgSize; + HRESULT hr = DP_OK; + + dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody ); + + lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize ); + + lpMsgBody = (LPDPMSG_FORWARDADDPLAYER)( (BYTE*)lpMsg + + This->dp2->spData.dwSPHeaderSize ); + + /* Compose dplay message envelope */ + lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG; + lpMsgBody->envelope.wCommandId = DPMSGCMD_FORWARDADDPLAYER; + lpMsgBody->envelope.wVersion = DPMSGVER_DP6; + +#if 0 + { + LPBYTE lpPData; + DWORD dwDataSize; + + /* SP Player remote data needs to be propagated at some point - is this the point? */ + IDirectPlaySP_GetSPPlayerData( This->dp2->spData.lpISP, 0, (LPVOID*)&lpPData, &dwDataSize, DPSET_REMOTE ); + + ERR( "Player Data size is 0x%08lx\n" + "[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n" + "[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n", + + dwDataSize, + lpPData[0], lpPData[1], lpPData[2], lpPData[3], lpPData[4], + lpPData[5], lpPData[6], lpPData[7], lpPData[8], lpPData[9], + lpPData[10], lpPData[11], lpPData[12], lpPData[13], lpPData[14], + lpPData[15], lpPData[16], lpPData[17], lpPData[18], lpPData[19], + lpPData[20], lpPData[21], lpPData[22], lpPData[23], lpPData[24], + lpPData[25], lpPData[26], lpPData[27], lpPData[28], lpPData[29], + lpPData[30], lpPData[31] + ); + DebugBreak(); + } +#endif + + /* Compose body of message */ + lpMsgBody->dpidAppServer = dpidServer; + lpMsgBody->unknown2[0] = 0x0; + lpMsgBody->unknown2[1] = 0x1c; + lpMsgBody->unknown2[2] = 0x6c; + lpMsgBody->unknown2[3] = 0x50; + lpMsgBody->unknown2[4] = 0x9; + + lpMsgBody->dpidAppServer2 = dpidServer; + lpMsgBody->unknown3[0] = 0x0; + lpMsgBody->unknown3[0] = 0x0; + lpMsgBody->unknown3[0] = 0x20; + lpMsgBody->unknown3[0] = 0x0; + lpMsgBody->unknown3[0] = 0x0; + + lpMsgBody->dpidAppServer3 = dpidServer; + lpMsgBody->unknown4[0] = 0x30; + lpMsgBody->unknown4[1] = 0xb; + lpMsgBody->unknown4[2] = 0x0; + + lpMsgBody->unknown4[3] = NS_GetNsMagic( This->dp2->lpNameServerData ) - + 0x02000000; + TRACE( "Setting first magic to 0x%08lx\n", lpMsgBody->unknown4[3] ); + + lpMsgBody->unknown4[4] = 0x0; + lpMsgBody->unknown4[5] = 0x0; + lpMsgBody->unknown4[6] = 0x0; + +#if 0 + lpMsgBody->unknown4[7] = NS_GetOtherMagic( This->dp2->lpNameServerData ) +#else + lpMsgBody->unknown4[7] = NS_GetNsMagic( This->dp2->lpNameServerData ); +#endif + TRACE( "Setting second magic to 0x%08lx\n", lpMsgBody->unknown4[7] ); + + lpMsgBody->unknown4[8] = 0x0; + lpMsgBody->unknown4[9] = 0x0; + lpMsgBody->unknown4[10] = 0x0; + lpMsgBody->unknown4[11] = 0x0; + + lpMsgBody->unknown5[0] = 0x0; + lpMsgBody->unknown5[1] = 0x0; + + /* Send the message */ + { + DPSP_SENDDATA data; + + data.dwFlags = DPSEND_GUARANTEED; + data.idPlayerTo = 0; /* Name server */ + data.idPlayerFrom = dpidServer; /* Sending from session server */ + data.lpMessage = lpMsg; + data.dwMessageSize = dwMsgSize; + data.bSystemMessage = TRUE; /* Allow reply to be sent */ + data.lpISP = This->dp2->spData.lpISP; + + TRACE( "Sending forward player request with 0x%08lx\n", dpidServer ); + + lpMsg = DP_MSG_ExpectReply( This, &data, + DPMSG_WAIT_60_SECS, + DPMSGCMD_GETNAMETABLEREPLY, + &lpMsg, &dwMsgSize ); + } + + /* Need to examine the data and extract the new player id */ + if( lpMsg != NULL ) + { + FIXME( "Name Table reply received: stub\n" ); + } + + return hr; +} + +/* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does + * not seem to offer any way of uniquely differentiating between replies of the same type + * relative to the request sent. There is an implicit assumption that there will be no + * ordering issues on sends and receives from the opposite machine. No wonder MS is not + * a networking company. + */ +static +LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA lpData, + DWORD dwWaitTime, WORD wReplyCommandId, + LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize ) +{ + HRESULT hr; + HANDLE hMsgReceipt; + DP_MSG_REPLY_STRUCT_LIST replyStructList; + DWORD dwWaitReturn; + + /* Setup for receipt */ + hMsgReceipt = DP_MSG_BuildAndLinkReplyStruct( This, &replyStructList, + wReplyCommandId ); + + TRACE( "Sending msg and expecting cmd %u in reply within %lu ticks\n", + wReplyCommandId, dwWaitTime ); + hr = (*This->dp2->spData.lpCB->Send)( lpData ); + + if( FAILED(hr) ) + { + ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr ) ); + return NULL; + } + + /* The reply message will trigger the hMsgReceipt event effectively switching + * control back to this thread. See DP_MSG_ReplyReceived. + */ + dwWaitReturn = WaitForSingleObject( hMsgReceipt, dwWaitTime ); + if( dwWaitReturn != WAIT_OBJECT_0 ) + { + ERR( "Wait failed 0x%08lx\n", dwWaitReturn ); + return NULL; + } + + /* Clean Up */ + return DP_MSG_CleanReplyStruct( &replyStructList, lplpReplyMsg, lpdwMsgBodySize ); +} + +/* Determine if there is a matching request for this incoming message and then copy + * all important data. It is quite silly to have to copy the message, but the documents + * indicate that a copy is taken. Silly really. + */ +void DP_MSG_ReplyReceived( IDirectPlay2AImpl* This, WORD wCommandId, + LPCVOID lpcMsgBody, DWORD dwMsgBodySize ) +{ + LPDP_MSG_REPLY_STRUCT_LIST lpReplyList; + +#if 0 + if( wCommandId == DPMSGCMD_FORWARDADDPLAYER ) + { + DebugBreak(); + } +#endif + + /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to + * avoid problems. + */ + EnterCriticalSection( &This->unk->DP_lock ); + DPQ_REMOVE_ENTRY( This->dp2->replysExpected, replysExpected, replyExpected.wExpectedReply,\ + ==, wCommandId, lpReplyList ); + LeaveCriticalSection( &This->unk->DP_lock ); + + if( lpReplyList != NULL ) + { + lpReplyList->replyExpected.dwMsgBodySize = dwMsgBodySize; + lpReplyList->replyExpected.lpReplyMsg = HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + dwMsgBodySize ); + CopyMemory( lpReplyList->replyExpected.lpReplyMsg, + lpcMsgBody, dwMsgBodySize ); + + /* Signal the thread which sent the message that it has a reply */ + SetEvent( lpReplyList->replyExpected.hReceipt ); + } + else + { + ERR( "No receipt event set - only expecting in reply mode\n" ); + DebugBreak(); + } +} + +void DP_MSG_ToSelf( IDirectPlay2AImpl* This, DPID dpidSelf ) +{ + LPVOID lpMsg; + LPDPMSG_SENDENVELOPE lpMsgBody; + DWORD dwMsgSize; + + dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody ); + + lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize ); + + lpMsgBody = (LPDPMSG_SENDENVELOPE)( (BYTE*)lpMsg + + This->dp2->spData.dwSPHeaderSize ); + + /* Compose dplay message envelope */ + lpMsgBody->dwMagic = DPMSGMAGIC_DPLAYMSG; + lpMsgBody->wCommandId = DPMSGCMD_JUSTENVELOPE; + lpMsgBody->wVersion = DPMSGVER_DP6; + + /* Send the message to ourselves */ + { + DPSP_SENDDATA data; + + data.dwFlags = 0; + data.idPlayerTo = dpidSelf; /* Sending to session server */ + data.idPlayerFrom = 0; /* Sending from session server */ + data.lpMessage = lpMsg; + data.dwMessageSize = dwMsgSize; + data.bSystemMessage = TRUE; /* Allow reply to be sent */ + data.lpISP = This->dp2->spData.lpISP; + + lpMsg = DP_MSG_ExpectReply( This, &data, + DPMSG_WAIT_5_SECS, + DPMSGCMD_JUSTENVELOPE, + &lpMsg, &dwMsgSize ); + } +} + +void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId, + LPCVOID lpMsgBody, DWORD dwMsgBodySize ) +{ + LPCDPMSG_FORWARDADDPLAYERNACK lpcErrorMsg; + + lpcErrorMsg = (LPCDPMSG_FORWARDADDPLAYERNACK)lpMsgBody; + + ERR( "Received error message %u. Error is %s\n", + wCommandId, DPLAYX_HresultToString( lpcErrorMsg->errorCode) ); + DebugBreak(); +} diff --git a/reactos/lib/dplayx/dplayx_messages.h b/reactos/lib/dplayx/dplayx_messages.h new file mode 100644 index 00000000000..9ff109787ff --- /dev/null +++ b/reactos/lib/dplayx/dplayx_messages.h @@ -0,0 +1,223 @@ +/* + * Copyright 2000 Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_DPLAYX_MESSAGES__ +#define __WINE_DPLAYX_MESSAGES__ + +#include + +#include "windef.h" +#include "winbase.h" +#include "dplay.h" +#include "rpc.h" /* For GUID */ + +#include "dplay_global.h" + +DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart, + HANDLE hDeath, HANDLE hConnRead ); + +HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags, + LPDPID lpdipidAllocatedId ); +HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer ); + +void DP_MSG_ReplyReceived( IDirectPlay2AImpl* This, WORD wCommandId, + LPCVOID lpMsgBody, DWORD dwMsgBodySize ); +void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId, + LPCVOID lpMsgBody, DWORD dwMsgBodySize ); +void DP_MSG_ToSelf( IDirectPlay2AImpl* This, DPID dpidSelf ); + +/* Timings -> 1000 ticks/sec */ +#define DPMSG_WAIT_5_SECS 5000 +#define DPMSG_WAIT_30_SECS 30000 +#define DPMSG_WAIT_60_SECS 60000 +#define DPMSG_DEFAULT_WAIT_TIME DPMSG_WAIT_30_SECS + +/* 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_GETNAMETABLEREPLY 3 /* Contains all existing players in session */ + +#define DPMSGCMD_REQUESTNEWPLAYERID 5 + +#define DPMSGCMD_NEWPLAYERIDREPLY 7 +#define DPMSGCMD_CREATESESSION 8 /* Might be a create nameserver or new player msg */ +#define DPMSGCMD_CREATENEWPLAYER 9 +#define DPMSGCMD_SYSTEMMESSAGE 10 +#define DPMSGCMD_DELETEPLAYER 11 +#define DPMSGCMD_DELETEGROUP 12 + +#define DPMSGCMD_ENUMGROUPS 17 + +#define DPMSGCMD_FORWARDADDPLAYER 19 + +#define DPMSGCMD_PLAYERCHAT 22 + +#define DPMSGCMD_FORWARDADDPLAYERNACK 36 + +#define DPMSGCMD_JUSTENVELOPE 1000 +#define DPMSGCMD_JUSTENVELOPEREPLY 1001 + +/* 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 8 bytes + */ +typedef struct tagDPMSG_SENDENVELOPE +{ + DWORD dwMagic; + WORD wCommandId; + WORD wVersion; +} DPMSG_SENDENVELOPE, *LPDPMSG_SENDENVELOPE; +typedef const DPMSG_SENDENVELOPE* LPCDPMSG_SENDENVELOPE; + +/* System messages exchanged between players seems to have this + * payload envelope on top of the basic envelope + */ +typedef struct tagDPMSG_SYSMSGENVELOPE +{ + DWORD dwPlayerFrom; + DWORD dwPlayerTo; +} DPMSG_SYSMSGENVELOPE, *LPDPMSG_SYSMSGENVELOPE; +typedef const DPMSG_SYSMSGENVELOPE* LPCDPMSG_SYSMSGENVELOPE; + +/* Reply sent in response to an enumsession request */ +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; + +/* Msg sent to find out what sessions are available */ +typedef struct tagDPMSG_ENUMSESSIONSREQUEST +{ + DPMSG_SENDENVELOPE envelope; + + GUID guidApplication; + + DWORD dwPasswordSize; /* A Guess. This is 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; + +/* 12 bytes msg */ +typedef struct tagDPMSG_REQUESTNEWPLAYERID +{ + DPMSG_SENDENVELOPE envelope; + + DWORD dwFlags; /* dwFlags used for CreatePlayer */ + +} DPMSG_REQUESTNEWPLAYERID, *LPDPMSG_REQUESTNEWPLAYERID; +typedef const DPMSG_REQUESTNEWPLAYERID* LPCDPMSG_REQUESTNEWPLAYERID; + +/* 48 bytes msg */ +typedef struct tagDPMSG_NEWPLAYERIDREPLY +{ + DPMSG_SENDENVELOPE envelope; + + DPID dpidNewPlayerId; + + /* Assume that this is data that is tacked on to the end of the message + * that comes from the SP remote data stored that needs to be propagated. + */ + BYTE unknown[36]; /* This appears to always be 0 - not sure though */ +} DPMSG_NEWPLAYERIDREPLY, *LPDPMSG_NEWPLAYERIDREPLY; +typedef const DPMSG_NEWPLAYERIDREPLY* LPCDPMSG_NEWPLAYERIDREPLY; + +typedef struct tagDPMSG_FORWARDADDPLAYER +{ + DPMSG_SENDENVELOPE envelope; + + DWORD unknown; /* 0 */ + + DPID dpidAppServer; /* Remote application server id */ + DWORD unknown2[5]; /* 0x0, 0x1c, 0x6c, 0x50, 0x9 */ + + DPID dpidAppServer2; /* Remote application server id again !? */ + DWORD unknown3[5]; /* 0x0, 0x0, 0x20, 0x0, 0x0 */ + + DPID dpidAppServer3; /* Remote application server id again !? */ + + DWORD unknown4[12]; /* ??? - Is this a clump of 5 and then 8? */ + /* NOTE: 1 byte in front of the two 0x??090002 entries changes! + * Is it a timestamp of some sort? 1st always smaller than + * other... + */ +#define FORWARDADDPLAYER_UNKNOWN4_INIT { 0x30, 0xb, 0x0, 0x1e090002, 0x0, 0x0, 0x0, 0x32090002, 0x0, 0x0, 0x0, 0x0 } + + BYTE unknown5[2]; /* 2 bytes at the end. This may be a part of something! ( 0x0, 0x0) */ + +} DPMSG_FORWARDADDPLAYER, *LPDPMSG_FORWARDADDPLAYER; +typedef const DPMSG_FORWARDADDPLAYER* LPCDPMSG_FORWARDADDPLAYER; + +/* This is an error message that can be received. Not sure if this is + * specifically for a forward add player or for all errors + */ +typedef struct tagDPMSG_FORWARDADDPLAYERNACK +{ + DPMSG_SENDENVELOPE envelope; + HRESULT errorCode; +} DPMSG_FORWARDADDPLAYERNACK, *LPDPMSG_FORWARDADDPLAYERNACK; +typedef const DPMSG_FORWARDADDPLAYERNACK* LPCDPMSG_FORWARDADDPLAYERNACK; + +#include "poppack.h" + +#endif diff --git a/reactos/lib/dplayx/dplayx_queue.h b/reactos/lib/dplayx/dplayx_queue.h new file mode 100644 index 00000000000..814f684e6fa --- /dev/null +++ b/reactos/lib/dplayx/dplayx_queue.h @@ -0,0 +1,216 @@ +/* A queue definition based on sys/queue.h TAILQ definitions + * + * Copyright 2000 Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * o Linked list implementation for dplay/dplobby. Based off of the BSD + * version found in + * o Port it to ? + * + */ + +#ifndef __WINE_DPLAYX_QUEUE_H +#define __WINE_DPLAYX_QUEUE_H + +#include + +#include "windef.h" +#include "winbase.h" + +#define DPQ_INSERT(a,b,c) DPQ_INSERT_IN_TAIL(a,b,c) + +/* + * Tail queue definitions. + */ +#define DPQ_HEAD(type) \ +struct { \ + struct type *lpQHFirst; /* first element */ \ + struct type **lpQHLast; /* addr of last next element */ \ +} + +#define DPQ_ENTRY(type) \ +struct { \ + struct type *lpQNext; /* next element */ \ + struct type **lpQPrev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#define DPQ_INIT(head) \ +do{ \ + (head).lpQHFirst = NULL; \ + (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; \ + (elm)->field.lpQPrev = (head).lpQHLast; \ + *(head).lpQHLast = (elm); \ + (head).lpQHLast = &(elm)->field.lpQNext; \ +} while(0) + +/* Remove element from the queue */ +#define DPQ_REMOVE(head, elm, field) \ +do { \ + if (((elm)->field.lpQNext) != NULL) \ + (elm)->field.lpQNext->field.lpQPrev = \ + (elm)->field.lpQPrev; \ + else \ + (head).lpQHLast = (elm)->field.lpQPrev; \ + *(elm)->field.lpQPrev = (elm)->field.lpQNext; \ +} while(0) + +/* head - pointer to DPQ_HEAD struct + * elm - how to find the next element + * field - to be concatenated to rc to compare with fieldToCompare + * fieldToCompare - The value that we're comparing against + * 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, fieldCompareOperator, fieldToCompare, rc )\ +do { \ + (rc) = DPQ_FIRST(head); /* NULL head? */ \ + \ + while( rc ) \ + { \ + /* What we're searching for? */ \ + if( (rc)->field fieldCompareOperator (fieldToCompare) ) \ + { \ + break; /* rc == correct element */ \ + } \ + \ + /* End of list check */ \ + if( ( (rc) = (rc)->elm.lpQNext ) == (head).lpQHFirst ) \ + { \ + rc = NULL; \ + break; \ + } \ + } \ +} while(0) + +/* head - pointer to DPQ_HEAD struct + * elm - how to find the next element + * field - to be concatenated to rc to compare with fieldToCompare + * fieldToCompare - The value that we're comparing against + * compare_cb - Callback to invoke to determine if comparision should continue. + * Callback must be defined with DPQ_DECL_COMPARECB. + * rc - Variable to put the return code. Same type as (head).lpQHFirst + */ +#define DPQ_FIND_ENTRY_CB( head, elm, field, compare_cb, fieldToCompare, rc )\ +do { \ + (rc) = DPQ_FIRST(head); /* NULL head? */ \ + \ + while( rc ) \ + { \ + /* What we're searching for? */ \ + if( compare_cb( &((rc)->field), &(fieldToCompare) ) ) \ + { \ + break; /* no more */ \ + } \ + \ + /* End of list check */ \ + if( ( (rc) = (rc)->elm.lpQNext ) == (head).lpQHFirst ) \ + { \ + rc = NULL; \ + break; \ + } \ + } \ +} while(0) + +/* How to define the method to be passed to DPQ_DELETEQ */ +#define DPQ_DECL_COMPARECB( name, type ) BOOL name( const type* elem1, const type* elem2 ) + + +/* head - pointer to DPQ_HEAD struct + * elm - how to find the next element + * field - to be concatenated to rc to compare with fieldToEqual + * 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, fieldCompareOperator, fieldToCompare, rc )\ +do { \ + DPQ_FIND_ENTRY( head, elm, field, fieldCompareOperator, fieldToCompare, rc );\ + \ + /* Was the element found? */ \ + if( rc ) \ + { \ + DPQ_REMOVE( head, rc, elm ); \ + } \ +} while(0) + +/* head - pointer to DPQ_HEAD struct + * elm - how to find the next element + * field - to be concatenated to rc to compare with fieldToCompare + * fieldToCompare - The value that we're comparing against + * compare_cb - Callback to invoke to determine if comparision should continue. + * Callback must be defined with DPQ_DECL_COMPARECB. + * rc - Variable to put the return code. Same type as (head).lpQHFirst + */ +#define DPQ_REMOVE_ENTRY_CB( head, elm, field, compare_cb, fieldToCompare, rc )\ +do { \ + DPQ_FIND_ENTRY_CB( head, elm, field, compare_cb, fieldToCompare, rc );\ + \ + /* Was the element found? */ \ + if( rc ) \ + { \ + DPQ_REMOVE( head, rc, elm ); \ + } \ +} while(0) + + +/* Delete the entire queue + * head - pointer to the head of the queue + * field - field to access the next elements of the queue + * type - type of the pointer to the element element + * df - a delete function to be called. Declared with DPQ_DECL_DELETECB. + */ +#define DPQ_DELETEQ( head, field, type, df ) \ +do \ +{ \ + while( !DPQ_IS_EMPTY(head) ) \ + { \ + type holder = DPQ_FIRST(head); \ + DPQ_REMOVE( head, holder, field ); \ + df( holder ); \ + } \ +} while(0) + +/* How to define the method to be passed to DPQ_DELETEQ */ +#define DPQ_DECL_DELETECB( name, type ) void name( type elem ) + +/* 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/reactos/lib/dplayx/dplobby.c b/reactos/lib/dplayx/dplobby.c new file mode 100644 index 00000000000..1b836578bbb --- /dev/null +++ b/reactos/lib/dplayx/dplobby.c @@ -0,0 +1,2012 @@ +/* Direct Play Lobby 2 & 3 Implementation + * + * Copyright 1998,1999,2000 - Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "winnls.h" +#include "wine/debug.h" + +#include "dplayx_global.h" +#include "dplayx_messages.h" +#include "dplayx_queue.h" +#include "dplobby.h" +#include "dpinit.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +typedef struct IDirectPlayLobbyImpl IDirectPlayLobbyAImpl; +typedef struct IDirectPlayLobbyImpl IDirectPlayLobbyWImpl; +typedef struct IDirectPlayLobby2Impl IDirectPlayLobby2AImpl; +typedef struct IDirectPlayLobby2Impl IDirectPlayLobby2WImpl; +typedef struct IDirectPlayLobby3Impl IDirectPlayLobby3AImpl; +typedef struct IDirectPlayLobby3Impl IDirectPlayLobby3WImpl; + +/* Forward declarations for this module helper methods */ +HRESULT DPL_CreateCompoundAddress ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount, + LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface ); + +HRESULT DPL_CreateAddress( REFGUID guidSP, REFGUID guidDataType, LPCVOID lpData, DWORD dwDataSize, + LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface ); + + + +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 ); + + +/***************************************************************************** + * IDirectPlayLobby {1,2,3} 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 + * a lot 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. + * + */ +struct DPLMSG +{ + DPQ_ENTRY( DPLMSG ) msgs; /* Link to next queued message */ +}; +typedef struct DPLMSG* LPDPLMSG; + +typedef struct tagDirectPlayLobbyIUnknownData +{ + LONG 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 +{ + BOOL dummy; +} DirectPlayLobby2Data; + +typedef struct tagDirectPlayLobby3Data +{ + BOOL dummy; +} DirectPlayLobby3Data; + +#define DPL_IMPL_FIELDS \ + LONG ulInterfaceRef; \ + DirectPlayLobbyIUnknownData* unk; \ + DirectPlayLobbyData* dpl; \ + DirectPlayLobby2Data* dpl2; \ + DirectPlayLobby3Data* dpl3; + +struct IDirectPlayLobbyImpl +{ + const IDirectPlayLobbyVtbl *lpVtbl; + DPL_IMPL_FIELDS +}; + +struct IDirectPlayLobby2Impl +{ + const IDirectPlayLobby2Vtbl *lpVtbl; + DPL_IMPL_FIELDS +}; + +struct IDirectPlayLobby3Impl +{ + const IDirectPlayLobby3Vtbl *lpVtbl; + DPL_IMPL_FIELDS +}; + +/* Forward declarations of virtual tables */ +static const IDirectPlayLobbyVtbl directPlayLobbyWVT; +static const IDirectPlayLobby2Vtbl directPlayLobby2WVT; +static const IDirectPlayLobby3Vtbl directPlayLobby3WVT; + +static const IDirectPlayLobbyVtbl directPlayLobbyAVT; +static const IDirectPlayLobby2Vtbl directPlayLobby2AVT; +static const IDirectPlayLobby3Vtbl directPlayLobby3AVT; + +static BOOL DPL_CreateIUnknown( LPVOID lpDPL ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)lpDPL; + + This->unk = 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 ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)lpDPL; + + DeleteCriticalSection( &This->unk->DPL_lock ); + HeapFree( GetProcessHeap(), 0, This->unk ); + + return TRUE; +} + +static BOOL DPL_CreateLobby1( LPVOID lpDPL ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)lpDPL; + + This->dpl = 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 ) +{ + IDirectPlayLobbyAImpl *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 ) +{ + IDirectPlayLobby2AImpl *This = (IDirectPlayLobby2AImpl *)lpDPL; + + This->dpl2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dpl2) ) ); + if ( This->dpl2 == NULL ) + { + return FALSE; + } + + return TRUE; +} + +static BOOL DPL_DestroyLobby2( LPVOID lpDPL ) +{ + IDirectPlayLobby2AImpl *This = (IDirectPlayLobby2AImpl *)lpDPL; + + HeapFree( GetProcessHeap(), 0, This->dpl2 ); + + return TRUE; +} + +static BOOL DPL_CreateLobby3( LPVOID lpDPL ) +{ + IDirectPlayLobby3AImpl *This = (IDirectPlayLobby3AImpl *)lpDPL; + + This->dpl3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dpl3) ) ); + if ( This->dpl3 == NULL ) + { + return FALSE; + } + + return TRUE; +} + +static BOOL DPL_DestroyLobby3( LPVOID lpDPL ) +{ + IDirectPlayLobby3AImpl *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. + * + * Snip from some Microsoft document: + * There are four requirements for implementations of QueryInterface (In these + * cases, "must succeed" means "must succeed barring catastrophic failure."): + * + * * The set of interfaces accessible on an object through + * IUnknown::QueryInterface must be static, not dynamic. This means that + * if a call to QueryInterface for a pointer to a specified interface + * succeeds the first time, it must succeed again, and if it fails the + * first time, it must fail on all subsequent queries. + * * It must be symmetric ~W if a client holds a pointer to an interface on + * an object, and queries for that interface, the call must succeed. + * * It must be reflexive ~W if a client holding a pointer to one interface + * queries successfully for another, a query through the obtained pointer + * for the first interface must succeed. + * * It must be transitive ~W if a client holding a pointer to one interface + * 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. + */ +extern +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 ) ) + { + IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)*ppvObj; + This->lpVtbl = &directPlayLobbyWVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobbyA, riid ) ) + { + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)*ppvObj; + This->lpVtbl = &directPlayLobbyAVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby2, riid ) ) + { + IDirectPlayLobby2WImpl *This = (IDirectPlayLobby2WImpl *)*ppvObj; + This->lpVtbl = &directPlayLobby2WVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby2A, riid ) ) + { + IDirectPlayLobby2AImpl *This = (IDirectPlayLobby2AImpl *)*ppvObj; + This->lpVtbl = &directPlayLobby2AVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby3, riid ) ) + { + IDirectPlayLobby3WImpl *This = (IDirectPlayLobby3WImpl *)*ppvObj; + This->lpVtbl = &directPlayLobby3WVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby3A, riid ) ) + { + IDirectPlayLobby3AImpl *This = (IDirectPlayLobby3AImpl *)*ppvObj; + This->lpVtbl = &directPlayLobby3AVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + 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; + } + + /* Initialize failed, destroy it */ + DPL_DestroyLobby3( *ppvObj ); + DPL_DestroyLobby2( *ppvObj ); + DPL_DestroyLobby1( *ppvObj ); + DPL_DestroyIUnknown( *ppvObj ); + HeapFree( GetProcessHeap(), 0, *ppvObj ); + + *ppvObj = NULL; + return DPERR_NOMEMORY; +} + +static HRESULT WINAPI DPL_QueryInterface +( LPDIRECTPLAYLOBBYA iface, + REFIID riid, + LPVOID* ppvObj ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; + TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj ); + + *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *This ) ); + + if( *ppvObj == NULL ) + { + return DPERR_OUTOFMEMORY; + } + + CopyMemory( *ppvObj, This, sizeof( *This ) ); + (*(IDirectPlayLobbyAImpl**)ppvObj)->ulInterfaceRef = 0; + + if( IsEqualGUID( &IID_IDirectPlayLobby, riid ) ) + { + IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)*ppvObj; + This->lpVtbl = &directPlayLobbyWVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobbyA, riid ) ) + { + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)*ppvObj; + This->lpVtbl = &directPlayLobbyAVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby2, riid ) ) + { + IDirectPlayLobby2WImpl *This = (IDirectPlayLobby2WImpl *)*ppvObj; + This->lpVtbl = &directPlayLobby2WVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby2A, riid ) ) + { + IDirectPlayLobby2AImpl *This = (IDirectPlayLobby2AImpl *)*ppvObj; + This->lpVtbl = &directPlayLobby2AVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby3, riid ) ) + { + IDirectPlayLobby3WImpl *This = (IDirectPlayLobby3WImpl *)*ppvObj; + This->lpVtbl = &directPlayLobby3WVT; + } + else if( IsEqualGUID( &IID_IDirectPlayLobby3A, riid ) ) + { + IDirectPlayLobby3AImpl *This = (IDirectPlayLobby3AImpl *)*ppvObj; + This->lpVtbl = &directPlayLobby3AVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + return E_NOINTERFACE; + } + + 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 DPL_AddRef +( LPDIRECTPLAYLOBBY iface ) +{ + ULONG ulInterfaceRefCount, ulObjRefCount; + IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)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; +} + +/* + * Simple COM procedure. Decrease the reference count to this object. + * If the object no longer has any reference counts, free up the associated + * memory. + */ +static ULONG WINAPI DPL_Release +( LPDIRECTPLAYLOBBYA iface ) +{ + ULONG ulInterfaceRefCount, ulObjRefCount; + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)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 ) + { + DPL_DestroyLobby3( This ); + DPL_DestroyLobby2( This ); + DPL_DestroyLobby1( This ); + DPL_DestroyIUnknown( This ); + } + + if( ulInterfaceRefCount == 0 ) + { + HeapFree( GetProcessHeap(), 0, This ); + } + + return ulInterfaceRefCount; +} + + +/******************************************************************** + * + * Connects an application to the session specified by the DPLCONNECTION + * structure currently stored with the DirectPlayLobby object. + * + * Returns an IDirectPlay interface. + * + */ +static HRESULT WINAPI DPL_ConnectEx +( IDirectPlayLobbyAImpl* This, + DWORD dwFlags, + REFIID riid, + LPVOID* lplpDP, + IUnknown* pUnk) +{ + HRESULT hr; + DWORD dwOpenFlags = 0; + DWORD dwConnSize = 0; + LPDPLCONNECTION lpConn; + + FIXME("(%p)->(0x%08lx,%p,%p): semi stub\n", This, dwFlags, lplpDP, pUnk ); + + if( pUnk ) + { + return DPERR_INVALIDPARAMS; + } + + /* Backwards compatibility */ + if( dwFlags == 0 ) + { + dwFlags = DPCONNECT_RETURNSTATUS; + } + + /* Create the DirectPlay interface */ + if( ( hr = DP_CreateInterface( riid, lplpDP ) ) != DP_OK ) + { + ERR( "error creating interface for %s:%s.\n", + debugstr_guid( riid ), DPLAYX_HresultToString( hr ) ); + return hr; + } + + /* FIXME: Is it safe/correct to use appID of 0? */ + hr = IDirectPlayLobby_GetConnectionSettings( (LPDIRECTPLAYLOBBY)This, + 0, NULL, &dwConnSize ); + if( hr != DPERR_BUFFERTOOSMALL ) + { + return hr; + } + + lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwConnSize ); + + if( lpConn == NULL ) + { + return DPERR_NOMEMORY; + } + + /* FIXME: Is it safe/correct to use appID of 0? */ + hr = IDirectPlayLobby_GetConnectionSettings( (LPDIRECTPLAYLOBBY)This, + 0, lpConn, &dwConnSize ); + if( FAILED( hr ) ) + { + HeapFree( GetProcessHeap(), 0, lpConn ); + 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 ) + { + dwOpenFlags |= DPOPEN_RETURNSTATUS; + } + dwOpenFlags |= lpConn->dwFlags; + + hr = IDirectPlayX_Open( (*(LPDIRECTPLAY2*)lplpDP), lpConn->lpSessionDesc, + dwOpenFlags ); + + HeapFree( GetProcessHeap(), 0, lpConn ); + + return hr; +} + +static HRESULT WINAPI IDirectPlayLobbyAImpl_Connect +( LPDIRECTPLAYLOBBYA iface, + DWORD dwFlags, + LPDIRECTPLAY2A* lplpDP, + IUnknown* pUnk) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; + return DPL_ConnectEx( This, dwFlags, &IID_IDirectPlay2A, + (LPVOID)lplpDP, pUnk ); +} + +static HRESULT WINAPI IDirectPlayLobbyWImpl_Connect +( LPDIRECTPLAYLOBBY iface, + DWORD dwFlags, + LPDIRECTPLAY2* lplpDP, + IUnknown* pUnk) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; /* Yes cast to A */ + return DPL_ConnectEx( This, dwFlags, &IID_IDirectPlay2, + (LPVOID)lplpDP, pUnk ); +} + +/******************************************************************** + * + * Creates a DirectPlay Address, given a service provider-specific network + * address. + * Returns an address contains the globally unique identifier + * (GUID) of the service provider and data that the service provider can + * interpret as a network address. + * + * NOTE: It appears that this method is supposed to be really really stupid + * with no error checking on the contents. + */ +static HRESULT WINAPI IDirectPlayLobbyAImpl_CreateAddress +( LPDIRECTPLAYLOBBYA iface, + REFGUID guidSP, + REFGUID guidDataType, + LPCVOID lpData, + DWORD dwDataSize, + LPVOID lpAddress, + LPDWORD lpdwAddressSize ) +{ + return DPL_CreateAddress( guidSP, guidDataType, lpData, dwDataSize, + lpAddress, lpdwAddressSize, TRUE ); +} + +static HRESULT WINAPI IDirectPlayLobbyWImpl_CreateAddress +( LPDIRECTPLAYLOBBY iface, + REFGUID guidSP, + REFGUID guidDataType, + LPCVOID lpData, + DWORD dwDataSize, + LPVOID lpAddress, + LPDWORD lpdwAddressSize ) +{ + return DPL_CreateAddress( guidSP, guidDataType, lpData, dwDataSize, + lpAddress, lpdwAddressSize, FALSE ); +} + +HRESULT DPL_CreateAddress( + REFGUID guidSP, + REFGUID guidDataType, + LPCVOID lpData, + DWORD dwDataSize, + LPVOID lpAddress, + LPDWORD lpdwAddressSize, + BOOL bAnsiInterface ) +{ + const DWORD dwNumAddElements = 2; /* Service Provide & address data type */ + DPCOMPOUNDADDRESSELEMENT addressElements[ 2 /* dwNumAddElements */ ]; + + TRACE( "(%p)->(%p,%p,0x%08lx,%p,%p,%d)\n", guidSP, guidDataType, lpData, dwDataSize, + lpAddress, lpdwAddressSize, bAnsiInterface ); + + addressElements[ 0 ].guidDataType = DPAID_ServiceProvider; + addressElements[ 0 ].dwDataSize = sizeof( GUID ); + addressElements[ 0 ].lpData = (LPVOID)guidSP; + + addressElements[ 1 ].guidDataType = *guidDataType; + addressElements[ 1 ].dwDataSize = dwDataSize; + addressElements[ 1 ].lpData = (LPVOID)lpData; + + /* Call CreateCompoundAddress to cut down on code. + NOTE: We can do this because we don't support DPL 1 interfaces! */ + return DPL_CreateCompoundAddress( addressElements, dwNumAddElements, + lpAddress, lpdwAddressSize, bAnsiInterface ); +} + + + +/******************************************************************** + * + * Parses out chunks from the DirectPlay Address buffer by calling the + * given callback function, with lpContext, for each of the chunks. + * + */ +static HRESULT WINAPI IDirectPlayLobbyAImpl_EnumAddress +( LPDIRECTPLAYLOBBYA iface, + LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, + LPCVOID lpAddress, + DWORD dwAddressSize, + LPVOID lpContext ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; + + TRACE("(%p)->(%p,%p,0x%08lx,%p)\n", This, lpEnumAddressCallback, lpAddress, + dwAddressSize, lpContext ); + + return DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext ); +} + +static HRESULT WINAPI IDirectPlayLobbyWImpl_EnumAddress +( LPDIRECTPLAYLOBBY iface, + LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, + LPCVOID lpAddress, + DWORD dwAddressSize, + LPVOID lpContext ) +{ + IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; + + TRACE("(%p)->(%p,%p,0x%08lx,%p)\n", This, lpEnumAddressCallback, lpAddress, + dwAddressSize, lpContext ); + + return DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext ); +} + +extern HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, + DWORD dwAddressSize, LPVOID lpContext ) +{ + DWORD dwTotalSizeEnumerated = 0; + + /* FIXME: First chunk is always the total size chunk - Should we report it? */ + + while ( dwTotalSizeEnumerated < dwAddressSize ) + { + const DPADDRESS* lpElements = (const DPADDRESS*)lpAddress; + DWORD dwSizeThisEnumeration; + + /* Invoke the enum method. If false is returned, stop enumeration */ + if ( !lpEnumAddressCallback( &lpElements->guidDataType, + lpElements->dwDataSize, + (BYTE*)lpElements + sizeof( DPADDRESS ), + lpContext ) ) + { + break; + } + + dwSizeThisEnumeration = sizeof( DPADDRESS ) + lpElements->dwDataSize; + lpAddress = (const BYTE*) lpAddress + dwSizeThisEnumeration; + dwTotalSizeEnumerated += dwSizeThisEnumeration; + } + + return DP_OK; +} + +/******************************************************************** + * + * Enumerates all the address types that a given service provider needs to + * build the DirectPlay Address. + * + */ +static HRESULT WINAPI IDirectPlayLobbyAImpl_EnumAddressTypes +( LPDIRECTPLAYLOBBYA iface, + LPDPLENUMADDRESSTYPESCALLBACK lpEnumAddressTypeCallback, + REFGUID guidSP, + LPVOID lpContext, + DWORD dwFlags ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; + + HKEY hkResult; + LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers"; + DWORD dwIndex, sizeOfSubKeyName=50; + char subKeyName[51]; + FILETIME filetime; + + TRACE(" (%p)->(%p,%p,%p,0x%08lx)\n", This, lpEnumAddressTypeCallback, guidSP, lpContext, dwFlags ); + + if( dwFlags != 0 ) + { + return DPERR_INVALIDPARAMS; + } + + if( !lpEnumAddressTypeCallback || !*lpEnumAddressTypeCallback ) + { + return DPERR_INVALIDPARAMS; + } + + if( guidSP == NULL ) + { + return DPERR_INVALIDOBJECT; + } + + /* 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 DP_OK; + } + + /* 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=50 ) + { + + HKEY hkServiceProvider, hkServiceProviderAt; + GUID serviceProviderGUID; + DWORD returnTypeGUID, sizeOfReturnBuffer = 50; + char atSubKey[51]; + char returnBuffer[51]; + WCHAR buff[51]; + DWORD dwAtIndex; + LPCSTR atKey = "Address Types"; + LPCSTR guidDataSubKey = "Guid"; + FILETIME filetime; + + + 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, &returnTypeGUID, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR(": missing GUID registry data members\n" ); + continue; + } + + /* FIXME: Check return types to ensure we're interpreting data right */ + MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) ); + CLSIDFromString( buff, &serviceProviderGUID ); + /* 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, guidSP ) ) + { + continue; + } + + /* Get a handle for this particular service provider */ + if( RegOpenKeyExA( hkServiceProvider, atKey, 0, KEY_READ, + &hkServiceProviderAt ) != ERROR_SUCCESS ) + { + TRACE(": No Address Types registry data sub key/members\n" ); + break; + } + + /* Traverse all the address type we have available */ + for( dwAtIndex=0; + RegEnumKeyExA( hkServiceProviderAt, dwAtIndex, atSubKey, &sizeOfSubKeyName, + NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS; + ++dwAtIndex, sizeOfSubKeyName=50 ) + { + TRACE( "Found Address Type GUID %s\n", atSubKey ); + + /* FIXME: Check return types to ensure we're interpreting data right */ + MultiByteToWideChar( CP_ACP, 0, atSubKey, -1, buff, sizeof(buff)/sizeof(WCHAR) ); + CLSIDFromString( buff, &serviceProviderGUID ); + /* FIXME: Have I got a memory leak on the serviceProviderGUID? */ + + /* The enumeration will return FALSE if we are not to continue */ + if( !lpEnumAddressTypeCallback( &serviceProviderGUID, lpContext, 0 ) ) + { + WARN("lpEnumCallback returning FALSE\n" ); + break; /* FIXME: This most likely has to break from the procedure...*/ + } + + } + + /* We only enumerate address types for 1 GUID. We've found it, so quit looking */ + break; + } + + return DP_OK; +} + +static HRESULT WINAPI IDirectPlayLobbyWImpl_EnumAddressTypes +( LPDIRECTPLAYLOBBY iface, + LPDPLENUMADDRESSTYPESCALLBACK lpEnumAddressTypeCallback, + REFGUID guidSP, + LPVOID lpContext, + DWORD dwFlags ) +{ + FIXME(":stub\n"); + return DPERR_OUTOFMEMORY; +} + +/******************************************************************** + * + * Enumerates what applications are registered with DirectPlay by + * invoking the callback function with lpContext. + * + */ +static HRESULT WINAPI IDirectPlayLobbyWImpl_EnumLocalApplications +( LPDIRECTPLAYLOBBY iface, + LPDPLENUMLOCALAPPLICATIONSCALLBACK lpEnumLocalAppCallback, + LPVOID lpContext, + DWORD dwFlags ) +{ + IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; + + FIXME("(%p)->(%p,%p,0x%08lx):stub\n", This, lpEnumLocalAppCallback, lpContext, dwFlags ); + + return DPERR_OUTOFMEMORY; +} + +static HRESULT WINAPI IDirectPlayLobbyAImpl_EnumLocalApplications +( LPDIRECTPLAYLOBBYA iface, + LPDPLENUMLOCALAPPLICATIONSCALLBACK lpEnumLocalAppCallback, + LPVOID lpContext, + DWORD dwFlags ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; + + HKEY hkResult; + LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Applications"; + LPCSTR guidDataSubKey = "Guid"; + DWORD dwIndex, sizeOfSubKeyName=50; + char subKeyName[51]; + FILETIME filetime; + + TRACE("(%p)->(%p,%p,0x%08lx)\n", This, lpEnumLocalAppCallback, lpContext, dwFlags ); + + if( dwFlags != 0 ) + { + return DPERR_INVALIDPARAMS; + } + + if( !lpEnumLocalAppCallback || !*lpEnumLocalAppCallback ) + { + return DPERR_INVALIDPARAMS; + } + + /* 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 DP_OK; + } + + /* Traverse all registered applications */ + for( dwIndex=0; + RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName, NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS; + ++dwIndex, sizeOfSubKeyName=50 ) + { + + HKEY hkServiceProvider; + GUID serviceProviderGUID; + DWORD returnTypeGUID, sizeOfReturnBuffer = 50; + char returnBuffer[51]; + WCHAR buff[51]; + DPLAPPINFO dplAppInfo; + + 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, &returnTypeGUID, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR(": missing GUID registry data members\n" ); + continue; + } + + /* FIXME: Check return types to ensure we're interpreting data right */ + MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) ); + CLSIDFromString( buff, &serviceProviderGUID ); + /* FIXME: Have I got a memory leak on the serviceProviderGUID? */ + + dplAppInfo.dwSize = sizeof( dplAppInfo ); + dplAppInfo.guidApplication = serviceProviderGUID; + dplAppInfo.u.lpszAppNameA = subKeyName; + + EnterCriticalSection( &This->unk->DPL_lock ); + + memcpy( &This->dpl->hkCallbackKeyHack, &hkServiceProvider, sizeof( hkServiceProvider ) ); + + if( !lpEnumLocalAppCallback( &dplAppInfo, lpContext, dwFlags ) ) + { + LeaveCriticalSection( &This->unk->DPL_lock ); + break; + } + + LeaveCriticalSection( &This->unk->DPL_lock ); + } + + return DP_OK; +} + +/******************************************************************** + * + * Retrieves the DPLCONNECTION structure that contains all the information + * needed to start and connect an application. This was generated using + * either the RunApplication or SetConnectionSettings methods. + * + * NOTES: If lpData is NULL then just return lpdwDataSize. This allows + * the data structure to be allocated by our caller which can then + * call this procedure/method again with a valid data pointer. + */ +static HRESULT WINAPI IDirectPlayLobbyAImpl_GetConnectionSettings +( LPDIRECTPLAYLOBBYA iface, + DWORD dwAppID, + LPVOID lpData, + LPDWORD lpdwDataSize ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; + HRESULT hr; + + TRACE("(%p)->(0x%08lx,%p,%p)\n", This, dwAppID, lpData, lpdwDataSize ); + + EnterCriticalSection( &This->unk->DPL_lock ); + + hr = DPLAYX_GetConnectionSettingsA( dwAppID, + lpData, + lpdwDataSize + ); + + LeaveCriticalSection( &This->unk->DPL_lock ); + + return hr; +} + +static HRESULT WINAPI IDirectPlayLobbyWImpl_GetConnectionSettings +( LPDIRECTPLAYLOBBY iface, + DWORD dwAppID, + LPVOID lpData, + LPDWORD lpdwDataSize ) +{ + IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; + HRESULT hr; + + TRACE("(%p)->(0x%08lx,%p,%p)\n", This, dwAppID, lpData, lpdwDataSize ); + + EnterCriticalSection( &This->unk->DPL_lock ); + + hr = DPLAYX_GetConnectionSettingsW( dwAppID, + lpData, + lpdwDataSize + ); + + LeaveCriticalSection( &This->unk->DPL_lock ); + + return hr; +} + +/******************************************************************** + * + * Retrieves the message sent between a lobby client and a DirectPlay + * application. All messages are queued until received. + * + */ +static HRESULT WINAPI IDirectPlayLobbyAImpl_ReceiveLobbyMessage +( LPDIRECTPLAYLOBBYA iface, + DWORD dwFlags, + DWORD dwAppID, + LPDWORD lpdwMessageFlags, + LPVOID lpData, + LPDWORD lpdwDataSize ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; + FIXME(":stub %p %08lx %08lx %p %p %p\n", This, dwFlags, dwAppID, lpdwMessageFlags, lpData, + lpdwDataSize ); + return DPERR_OUTOFMEMORY; +} + +static HRESULT WINAPI IDirectPlayLobbyWImpl_ReceiveLobbyMessage +( LPDIRECTPLAYLOBBY iface, + DWORD dwFlags, + DWORD dwAppID, + LPDWORD lpdwMessageFlags, + LPVOID lpData, + LPDWORD lpdwDataSize ) +{ + IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; + FIXME(":stub %p %08lx %08lx %p %p %p\n", This, dwFlags, dwAppID, lpdwMessageFlags, lpData, + lpdwDataSize ); + return DPERR_OUTOFMEMORY; +} + +typedef struct tagRunApplicationEnumStruct +{ + IDirectPlayLobbyAImpl* This; + + GUID appGUID; + LPSTR lpszPath; + LPSTR lpszFileName; + LPSTR lpszCommandLine; + LPSTR lpszCurrentDirectory; +} RunApplicationEnumStruct, *lpRunApplicationEnumStruct; + +/* To be called by RunApplication to find how to invoke the function */ +static BOOL CALLBACK RunApplicationA_EnumLocalApplications +( LPCDPLAPPINFO lpAppInfo, + LPVOID lpContext, + DWORD dwFlags ) +{ + lpRunApplicationEnumStruct lpData = (lpRunApplicationEnumStruct)lpContext; + + if( IsEqualGUID( &lpAppInfo->guidApplication, &lpData->appGUID ) ) + { + char returnBuffer[200]; + DWORD returnType, sizeOfReturnBuffer; + LPCSTR clSubKey = "CommandLine"; + LPCSTR cdSubKey = "CurrentDirectory"; + LPCSTR fileSubKey = "File"; + LPCSTR pathSubKey = "Path"; + + /* FIXME: Lazy man hack - dplay struct has the present reg key saved */ + + sizeOfReturnBuffer = 200; + + /* Get all the appropriate data from the registry */ + if( RegQueryValueExA( lpData->This->dpl->hkCallbackKeyHack, clSubKey, + NULL, &returnType, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR( ": missing CommandLine registry data member\n" ); + } + else + { + if ((lpData->lpszCommandLine = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 ))) + strcpy( lpData->lpszCommandLine, returnBuffer ); + } + + sizeOfReturnBuffer = 200; + + if( RegQueryValueExA( lpData->This->dpl->hkCallbackKeyHack, cdSubKey, + NULL, &returnType, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR( ": missing CurrentDirectory registry data member\n" ); + } + else + { + if ((lpData->lpszCurrentDirectory = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 ))) + strcpy( lpData->lpszCurrentDirectory, returnBuffer ); + } + + sizeOfReturnBuffer = 200; + + if( RegQueryValueExA( lpData->This->dpl->hkCallbackKeyHack, fileSubKey, + NULL, &returnType, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR( ": missing File registry data member\n" ); + } + else + { + if ((lpData->lpszFileName = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 ))) + strcpy( lpData->lpszFileName, returnBuffer ); + } + + sizeOfReturnBuffer = 200; + + if( RegQueryValueExA( lpData->This->dpl->hkCallbackKeyHack, pathSubKey, + NULL, &returnType, (LPBYTE)returnBuffer, + &sizeOfReturnBuffer ) != ERROR_SUCCESS ) + { + ERR( ": missing Path registry data member\n" ); + } + else + { + if ((lpData->lpszPath = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 ))) + strcpy( lpData->lpszPath, returnBuffer ); + } + + return FALSE; /* No need to keep going as we found what we wanted */ + } + + 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 = 0, hAppDeath = 0, hAppRead = 0; + SECURITY_ATTRIBUTES s_attrib; + + s_attrib.nLength = sizeof( s_attrib ); + s_attrib.lpSecurityDescriptor = NULL; + s_attrib.bInheritHandle = TRUE; + + *lphStart = CreateEventW( &s_attrib, TRUE, FALSE, NULL ); + *lphDeath = CreateEventW( &s_attrib, TRUE, FALSE, NULL ); + *lphRead = CreateEventW( &s_attrib, TRUE, FALSE, NULL ); + + 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 ) ) + ) + { + if (*lphStart) { CloseHandle(*lphStart); *lphStart = 0; } + if (*lphDeath) { CloseHandle(*lphDeath); *lphDeath = 0; } + if (*lphRead) { CloseHandle(*lphRead); *lphRead = 0; } + /* FIXME: Handle leak... */ + ERR( "Unable to dup handles\n" ); + return FALSE; + } + + if( !DPLAYX_SetLobbyHandles( dwDestProcessId, + hAppStart, hAppDeath, hAppRead ) ) + { + /* FIXME: Handle leak... */ + return FALSE; + } + + return TRUE; +} + + +/******************************************************************** + * + * Starts an application and passes to it all the information to + * connect to a session. + * + */ +static HRESULT WINAPI IDirectPlayLobbyAImpl_RunApplication +( LPDIRECTPLAYLOBBYA iface, + DWORD dwFlags, + LPDWORD lpdwAppID, + LPDPLCONNECTION lpConn, + HANDLE hReceiveEvent ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; + HRESULT hr; + RunApplicationEnumStruct enumData; + char temp[200]; + STARTUPINFOA startupInfo; + PROCESS_INFORMATION newProcessInfo; + LPSTR appName; + DWORD dwSuspendCount; + HANDLE hStart, hDeath, hSettingRead; + + TRACE( "(%p)->(0x%08lx,%p,%p,%p)\n", + This, dwFlags, lpdwAppID, lpConn, hReceiveEvent ); + + if( dwFlags != 0 ) + { + return DPERR_INVALIDPARAMS; + } + + if( DPLAYX_AnyLobbiesWaitingForConnSettings() ) + { + FIXME( "Waiting lobby not being handled correctly\n" ); + } + + EnterCriticalSection( &This->unk->DPL_lock ); + + ZeroMemory( &enumData, sizeof( enumData ) ); + enumData.This = This; + enumData.appGUID = lpConn->lpSessionDesc->guidApplication; + + /* Our callback function will fill up the enumData structure with all the information + required to start a new process */ + IDirectPlayLobby_EnumLocalApplications( iface, RunApplicationA_EnumLocalApplications, + (LPVOID)(&enumData), 0 ); + + /* First the application name */ + strcpy( temp, enumData.lpszPath ); + strcat( temp, "\\" ); + strcat( temp, enumData.lpszFileName ); + HeapFree( GetProcessHeap(), 0, enumData.lpszPath ); + HeapFree( GetProcessHeap(), 0, enumData.lpszFileName ); + if ((appName = HeapAlloc( GetProcessHeap(), 0, strlen(temp)+1 ))) strcpy( appName, temp ); + + /* Now the command line */ + strcat( temp, " " ); + strcat( temp, enumData.lpszCommandLine ); + HeapFree( GetProcessHeap(), 0, enumData.lpszCommandLine ); + if ((enumData.lpszCommandLine = HeapAlloc( GetProcessHeap(), 0, strlen(temp)+1 ))) + strcpy( enumData.lpszCommandLine, temp ); + + ZeroMemory( &startupInfo, sizeof( startupInfo ) ); + startupInfo.cb = sizeof( startupInfo ); + /* FIXME: Should any fields be filled in? */ + + ZeroMemory( &newProcessInfo, sizeof( newProcessInfo ) ); + + if( !CreateProcessA( appName, + enumData.lpszCommandLine, + NULL, + NULL, + FALSE, + CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE | CREATE_SUSPENDED, /* Creation Flags */ + NULL, + enumData.lpszCurrentDirectory, + &startupInfo, + &newProcessInfo + ) + ) + { + ERR( "Failed to create process for app %s\n", appName ); + + HeapFree( GetProcessHeap(), 0, appName ); + HeapFree( GetProcessHeap(), 0, enumData.lpszCommandLine ); + HeapFree( GetProcessHeap(), 0, enumData.lpszCurrentDirectory ); + + LeaveCriticalSection( &This->unk->DPL_lock ); + return DPERR_CANTCREATEPROCESS; + } + + HeapFree( GetProcessHeap(), 0, appName ); + HeapFree( GetProcessHeap(), 0, enumData.lpszCommandLine ); + HeapFree( GetProcessHeap(), 0, enumData.lpszCurrentDirectory ); + + /* Reserve this global application id! */ + if( !DPLAYX_CreateLobbyApplication( newProcessInfo.dwProcessId ) ) + { + ERR( "Unable to create global application data for 0x%08lx\n", + newProcessInfo.dwProcessId ); + } + + hr = IDirectPlayLobby_SetConnectionSettings( iface, 0, newProcessInfo.dwProcessId, lpConn ); + + if( hr != DP_OK ) + { + ERR( "SetConnectionSettings failure %s\n", DPLAYX_HresultToString( hr ) ); + LeaveCriticalSection( &This->unk->DPL_lock ); + return hr; + } + + /* Setup the handles for application notification */ + DPL_CreateAndSetLobbyHandles( newProcessInfo.dwProcessId, + newProcessInfo.hProcess, + &hStart, &hDeath, &hSettingRead ); + + /* 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 ) + { + ERR( "ResumeThread failed with 0x%08lx\n", dwSuspendCount ); + } + + return DP_OK; +} + +static HRESULT WINAPI IDirectPlayLobbyWImpl_RunApplication +( LPDIRECTPLAYLOBBY iface, + DWORD dwFlags, + LPDWORD lpdwAppID, + LPDPLCONNECTION lpConn, + HANDLE hReceiveEvent ) +{ + IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; + FIXME( "(%p)->(0x%08lx,%p,%p,%p):stub\n", This, dwFlags, lpdwAppID, lpConn, (void *)hReceiveEvent ); + return DPERR_OUTOFMEMORY; +} + +/******************************************************************** + * + * Sends a message between the application and the lobby client. + * All messages are queued until received. + * + */ +static HRESULT WINAPI IDirectPlayLobbyAImpl_SendLobbyMessage +( LPDIRECTPLAYLOBBYA iface, + DWORD dwFlags, + DWORD dwAppID, + LPVOID lpData, + DWORD dwDataSize ) +{ + FIXME(":stub\n"); + return DPERR_OUTOFMEMORY; +} + +static HRESULT WINAPI IDirectPlayLobbyWImpl_SendLobbyMessage +( LPDIRECTPLAYLOBBY iface, + DWORD dwFlags, + DWORD dwAppID, + LPVOID lpData, + DWORD dwDataSize ) +{ + FIXME(":stub\n"); + return DPERR_OUTOFMEMORY; +} + +/******************************************************************** + * + * Modifies the DPLCONNECTION structure to contain all information + * needed to start and connect an application. + * + */ +static HRESULT WINAPI IDirectPlayLobbyWImpl_SetConnectionSettings +( LPDIRECTPLAYLOBBY iface, + DWORD dwFlags, + DWORD dwAppID, + LPDPLCONNECTION lpConn ) +{ + IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; + HRESULT hr; + + TRACE("(%p)->(0x%08lx,0x%08lx,%p)\n", This, dwFlags, dwAppID, lpConn ); + + EnterCriticalSection( &This->unk->DPL_lock ); + + hr = DPLAYX_SetConnectionSettingsW( dwFlags, dwAppID, lpConn ); + + /* FIXME: Don't think that this is supposed to fail, but the docuementation + is somewhat sketchy. I'll try creating a lobby application + for this... */ + if( hr == DPERR_NOTLOBBIED ) + { + FIXME( "Unlobbied app setting connections. Is this correct behavior?\n" ); + if( dwAppID == 0 ) + { + dwAppID = GetCurrentProcessId(); + } + DPLAYX_CreateLobbyApplication( dwAppID ); + hr = DPLAYX_SetConnectionSettingsW( dwFlags, dwAppID, lpConn ); + } + + LeaveCriticalSection( &This->unk->DPL_lock ); + + return hr; +} + +static HRESULT WINAPI IDirectPlayLobbyAImpl_SetConnectionSettings +( LPDIRECTPLAYLOBBYA iface, + DWORD dwFlags, + DWORD dwAppID, + LPDPLCONNECTION lpConn ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; + HRESULT hr; + + TRACE("(%p)->(0x%08lx,0x%08lx,%p)\n", This, dwFlags, dwAppID, lpConn ); + + EnterCriticalSection( &This->unk->DPL_lock ); + + hr = DPLAYX_SetConnectionSettingsA( dwFlags, dwAppID, lpConn ); + + /* FIXME: Don't think that this is supposed to fail, but the docuementation + is somewhat sketchy. I'll try creating a lobby application + for this... */ + if( hr == DPERR_NOTLOBBIED ) + { + FIXME( "Unlobbied app setting connections. Is this correct behavior?\n" ); + dwAppID = GetCurrentProcessId(); + DPLAYX_CreateLobbyApplication( dwAppID ); + hr = DPLAYX_SetConnectionSettingsA( dwFlags, dwAppID, lpConn ); + } + + LeaveCriticalSection( &This->unk->DPL_lock ); + + return hr; +} + +/******************************************************************** + * + * Registers an event that will be set when a lobby message is received. + * + */ +static HRESULT WINAPI IDirectPlayLobbyAImpl_SetLobbyMessageEvent +( LPDIRECTPLAYLOBBYA iface, + DWORD dwFlags, + DWORD dwAppID, + HANDLE hReceiveEvent ) +{ + FIXME(":stub\n"); + return DPERR_OUTOFMEMORY; +} + +static HRESULT WINAPI IDirectPlayLobbyWImpl_SetLobbyMessageEvent +( LPDIRECTPLAYLOBBY iface, + DWORD dwFlags, + DWORD dwAppID, + HANDLE hReceiveEvent ) +{ + FIXME(":stub\n"); + return DPERR_OUTOFMEMORY; +} + + +/* DPL 2 methods */ +static HRESULT WINAPI IDirectPlayLobby2WImpl_CreateCompoundAddress +( LPDIRECTPLAYLOBBY2 iface, + LPCDPCOMPOUNDADDRESSELEMENT lpElements, + DWORD dwElementCount, + LPVOID lpAddress, + LPDWORD lpdwAddressSize ) +{ + return DPL_CreateCompoundAddress( lpElements, dwElementCount, lpAddress, lpdwAddressSize, FALSE ); +} + +static HRESULT WINAPI IDirectPlayLobby2AImpl_CreateCompoundAddress +( LPDIRECTPLAYLOBBY2A iface, + LPCDPCOMPOUNDADDRESSELEMENT lpElements, + DWORD dwElementCount, + LPVOID lpAddress, + LPDWORD lpdwAddressSize ) +{ + return DPL_CreateCompoundAddress( lpElements, dwElementCount, lpAddress, lpdwAddressSize, TRUE ); +} + +HRESULT DPL_CreateCompoundAddress +( LPCDPCOMPOUNDADDRESSELEMENT lpElements, + DWORD dwElementCount, + LPVOID lpAddress, + LPDWORD lpdwAddressSize, + BOOL bAnsiInterface ) +{ + DWORD dwSizeRequired = 0; + DWORD dwElements; + LPCDPCOMPOUNDADDRESSELEMENT lpOrigElements = lpElements; + + TRACE("(%p,0x%08lx,%p,%p)\n", lpElements, dwElementCount, lpAddress, lpdwAddressSize ); + + /* Parameter check */ + if( ( lpElements == NULL ) || + ( dwElementCount == 0 ) /* FIXME: Not sure if this is a failure case */ + ) + { + return DPERR_INVALIDPARAMS; + } + + /* Add the total size chunk */ + dwSizeRequired += sizeof( DPADDRESS ) + sizeof( DWORD ); + + /* Calculate the size of the buffer required */ + for ( dwElements = dwElementCount; dwElements > 0; --dwElements, ++lpElements ) + { + if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ServiceProvider ) ) || + ( IsEqualGUID( &lpElements->guidDataType, &DPAID_LobbyProvider ) ) + ) + { + dwSizeRequired += sizeof( DPADDRESS ) + sizeof( GUID ); + } + else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Phone ) ) || + ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Modem ) ) || + ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INet ) ) + ) + { + if( !bAnsiInterface ) + { + ERR( "Ansi GUIDs used for unicode interface\n" ); + return DPERR_INVALIDFLAGS; + } + + dwSizeRequired += sizeof( DPADDRESS ) + lpElements->dwDataSize; + } + else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_PhoneW ) ) || + ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ModemW ) ) || + ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetW ) ) + ) + { + if( bAnsiInterface ) + { + ERR( "Unicode GUIDs used for ansi interface\n" ); + return DPERR_INVALIDFLAGS; + } + + FIXME( "Right size for unicode interface?\n" ); + dwSizeRequired += sizeof( DPADDRESS ) + lpElements->dwDataSize * sizeof( WCHAR ); + } + else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetPort ) ) + { + dwSizeRequired += sizeof( DPADDRESS ) + sizeof( WORD ); + } + else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ComPort ) ) + { + FIXME( "Right size for unicode interface?\n" ); + dwSizeRequired += sizeof( DPADDRESS ) + sizeof( DPCOMPORTADDRESS ); /* FIXME: Right size? */ + } + else + { + ERR( "Unknown GUID %s\n", debugstr_guid(&lpElements->guidDataType) ); + return DPERR_INVALIDFLAGS; + } + } + + /* The user wants to know how big a buffer to allocate for us */ + if( ( lpAddress == NULL ) || + ( *lpdwAddressSize < dwSizeRequired ) + ) + { + *lpdwAddressSize = dwSizeRequired; + return DPERR_BUFFERTOOSMALL; + } + + /* Add the total size chunk */ + { + LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; + + CopyMemory( &lpdpAddress->guidDataType, &DPAID_TotalSize, sizeof( GUID ) ); + lpdpAddress->dwDataSize = sizeof( DWORD ); + lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); + + *(LPDWORD)lpAddress = dwSizeRequired; + lpAddress = (char *) lpAddress + sizeof( DWORD ); + } + + /* Calculate the size of the buffer required */ + for( dwElements = dwElementCount, lpElements = lpOrigElements; + dwElements > 0; + --dwElements, ++lpElements ) + { + if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ServiceProvider ) ) || + ( IsEqualGUID( &lpElements->guidDataType, &DPAID_LobbyProvider ) ) + ) + { + LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; + + CopyMemory( &lpdpAddress->guidDataType, &lpElements->guidDataType, + sizeof( GUID ) ); + lpdpAddress->dwDataSize = sizeof( GUID ); + lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); + + CopyMemory( lpAddress, lpElements->lpData, sizeof( GUID ) ); + lpAddress = (char *) lpAddress + sizeof( GUID ); + } + else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Phone ) ) || + ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Modem ) ) || + ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INet ) ) + ) + { + LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; + + CopyMemory( &lpdpAddress->guidDataType, &lpElements->guidDataType, + sizeof( GUID ) ); + lpdpAddress->dwDataSize = lpElements->dwDataSize; + lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); + + lstrcpynA( (LPSTR)lpAddress, + (LPCSTR)lpElements->lpData, + lpElements->dwDataSize ); + lpAddress = (char *) lpAddress + lpElements->dwDataSize; + } + else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_PhoneW ) ) || + ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ModemW ) ) || + ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetW ) ) + ) + { + LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; + + CopyMemory( &lpdpAddress->guidDataType, &lpElements->guidDataType, + sizeof( GUID ) ); + lpdpAddress->dwDataSize = lpElements->dwDataSize; + lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); + + lstrcpynW( (LPWSTR)lpAddress, + (LPCWSTR)lpElements->lpData, + lpElements->dwDataSize ); + lpAddress = (char *) lpAddress + lpElements->dwDataSize * sizeof( WCHAR ); + } + else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetPort ) ) + { + LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; + + CopyMemory( &lpdpAddress->guidDataType, &lpElements->guidDataType, + sizeof( GUID ) ); + lpdpAddress->dwDataSize = lpElements->dwDataSize; + lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); + + *((LPWORD)lpAddress) = *((LPWORD)lpElements->lpData); + lpAddress = (char *) lpAddress + sizeof( WORD ); + } + else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ComPort ) ) + { + LPDPADDRESS lpdpAddress = (LPDPADDRESS)lpAddress; + + CopyMemory( &lpdpAddress->guidDataType, &lpElements->guidDataType, + sizeof( GUID ) ); + lpdpAddress->dwDataSize = lpElements->dwDataSize; + lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); + + CopyMemory( lpAddress, lpElements->lpData, sizeof( DPADDRESS ) ); + lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); + } + } + + return DP_OK; +} + +/* DPL 3 methods */ + +static HRESULT WINAPI IDirectPlayLobby3WImpl_ConnectEx +( LPDIRECTPLAYLOBBY3 iface, DWORD dwFlags, REFIID riid, + LPVOID* lplpDP, IUnknown* pUnk ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface ; + return DPL_ConnectEx( This, dwFlags, riid, lplpDP, pUnk ); +} + +static HRESULT WINAPI IDirectPlayLobby3AImpl_ConnectEx +( LPDIRECTPLAYLOBBY3A iface, DWORD dwFlags, REFIID riid, + LPVOID* lplpDP, IUnknown* pUnk ) +{ + IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface ; + return DPL_ConnectEx( This, dwFlags, riid, lplpDP, pUnk ); +} + +static HRESULT WINAPI IDirectPlayLobby3WImpl_RegisterApplication +( LPDIRECTPLAYLOBBY3 iface, DWORD dwFlags, LPDPAPPLICATIONDESC lpAppDesc ) +{ + FIXME(":stub\n"); + return DP_OK; +} + +static HRESULT WINAPI IDirectPlayLobby3AImpl_RegisterApplication +( LPDIRECTPLAYLOBBY3A iface, DWORD dwFlags, LPDPAPPLICATIONDESC lpAppDesc ) +{ + FIXME(":stub\n"); + return DP_OK; +} + +static HRESULT WINAPI IDirectPlayLobby3WImpl_UnregisterApplication +( LPDIRECTPLAYLOBBY3 iface, DWORD dwFlags, REFGUID lpAppDesc ) +{ + FIXME(":stub\n"); + return DP_OK; +} + +static HRESULT WINAPI IDirectPlayLobby3AImpl_UnregisterApplication +( LPDIRECTPLAYLOBBY3A iface, DWORD dwFlags, REFGUID lpAppDesc ) +{ + FIXME(":stub\n"); + return DP_OK; +} + +static HRESULT WINAPI IDirectPlayLobby3WImpl_WaitForConnectionSettings +( LPDIRECTPLAYLOBBY3 iface, DWORD dwFlags ) +{ + HRESULT hr = DP_OK; + BOOL bStartWait = (dwFlags & DPLWAIT_CANCEL) ? FALSE : TRUE; + + TRACE( "(%p)->(0x%08lx)\n", iface, dwFlags ); + + if( DPLAYX_WaitForConnectionSettings( bStartWait ) ) + { + /* FIXME: What is the correct error return code? */ + hr = DPERR_NOTLOBBIED; + } + + return hr; +} + +static HRESULT WINAPI IDirectPlayLobby3AImpl_WaitForConnectionSettings +( LPDIRECTPLAYLOBBY3A iface, DWORD dwFlags ) +{ + HRESULT hr = DP_OK; + BOOL bStartWait = (dwFlags & DPLWAIT_CANCEL) ? FALSE : TRUE; + + TRACE( "(%p)->(0x%08lx)\n", iface, dwFlags ); + + if( DPLAYX_WaitForConnectionSettings( bStartWait ) ) + { + /* FIXME: What is the correct error return code? */ + hr = DPERR_NOTLOBBIED; + } + + return hr; +} + + +/* Virtual Table definitions for DPL{1,2,3}{A,W} */ + +/* Note: Hack so we can reuse the old functions without compiler warnings */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlayLobbyAVT.fun)) +#else +# define XCAST(fun) (void*) +#endif + +/* Direct Play Lobby 1 (ascii) Virtual Table for methods */ +/* All lobby 1 methods are exactly the same except QueryInterface */ +static const IDirectPlayLobbyVtbl directPlayLobbyAVT = +{ + + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, + + IDirectPlayLobbyAImpl_Connect, + IDirectPlayLobbyAImpl_CreateAddress, + IDirectPlayLobbyAImpl_EnumAddress, + IDirectPlayLobbyAImpl_EnumAddressTypes, + IDirectPlayLobbyAImpl_EnumLocalApplications, + IDirectPlayLobbyAImpl_GetConnectionSettings, + IDirectPlayLobbyAImpl_ReceiveLobbyMessage, + IDirectPlayLobbyAImpl_RunApplication, + IDirectPlayLobbyAImpl_SendLobbyMessage, + IDirectPlayLobbyAImpl_SetConnectionSettings, + IDirectPlayLobbyAImpl_SetLobbyMessageEvent +}; +#undef XCAST + + +/* Note: Hack so we can reuse the old functions without compiler warnings */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlayLobbyWVT.fun)) +#else +# define XCAST(fun) (void*) +#endif + +/* Direct Play Lobby 1 (unicode) Virtual Table for methods */ +static const IDirectPlayLobbyVtbl directPlayLobbyWVT = +{ + + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, + + IDirectPlayLobbyWImpl_Connect, + IDirectPlayLobbyWImpl_CreateAddress, + IDirectPlayLobbyWImpl_EnumAddress, + IDirectPlayLobbyWImpl_EnumAddressTypes, + IDirectPlayLobbyWImpl_EnumLocalApplications, + IDirectPlayLobbyWImpl_GetConnectionSettings, + IDirectPlayLobbyWImpl_ReceiveLobbyMessage, + IDirectPlayLobbyWImpl_RunApplication, + IDirectPlayLobbyWImpl_SendLobbyMessage, + IDirectPlayLobbyWImpl_SetConnectionSettings, + IDirectPlayLobbyWImpl_SetLobbyMessageEvent +}; +#undef XCAST + +/* Note: Hack so we can reuse the old functions without compiler warnings */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlayLobby2AVT.fun)) +#else +# define XCAST(fun) (void*) +#endif + +/* Direct Play Lobby 2 (ascii) Virtual Table for methods */ +static const IDirectPlayLobby2Vtbl directPlayLobby2AVT = +{ + + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, + + XCAST(Connect)IDirectPlayLobbyAImpl_Connect, + XCAST(CreateAddress)IDirectPlayLobbyAImpl_CreateAddress, + XCAST(EnumAddress)IDirectPlayLobbyAImpl_EnumAddress, + XCAST(EnumAddressTypes)IDirectPlayLobbyAImpl_EnumAddressTypes, + XCAST(EnumLocalApplications)IDirectPlayLobbyAImpl_EnumLocalApplications, + XCAST(GetConnectionSettings)IDirectPlayLobbyAImpl_GetConnectionSettings, + XCAST(ReceiveLobbyMessage)IDirectPlayLobbyAImpl_ReceiveLobbyMessage, + XCAST(RunApplication)IDirectPlayLobbyAImpl_RunApplication, + XCAST(SendLobbyMessage)IDirectPlayLobbyAImpl_SendLobbyMessage, + XCAST(SetConnectionSettings)IDirectPlayLobbyAImpl_SetConnectionSettings, + XCAST(SetLobbyMessageEvent)IDirectPlayLobbyAImpl_SetLobbyMessageEvent, + + IDirectPlayLobby2AImpl_CreateCompoundAddress +}; +#undef XCAST + +/* Note: Hack so we can reuse the old functions without compiler warnings */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlayLobby2AVT.fun)) +#else +# define XCAST(fun) (void*) +#endif + +/* Direct Play Lobby 2 (unicode) Virtual Table for methods */ +static const IDirectPlayLobby2Vtbl directPlayLobby2WVT = +{ + + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, + + XCAST(Connect)IDirectPlayLobbyWImpl_Connect, + XCAST(CreateAddress)IDirectPlayLobbyWImpl_CreateAddress, + XCAST(EnumAddress)IDirectPlayLobbyWImpl_EnumAddress, + XCAST(EnumAddressTypes)IDirectPlayLobbyWImpl_EnumAddressTypes, + XCAST(EnumLocalApplications)IDirectPlayLobbyWImpl_EnumLocalApplications, + XCAST(GetConnectionSettings)IDirectPlayLobbyWImpl_GetConnectionSettings, + XCAST(ReceiveLobbyMessage)IDirectPlayLobbyWImpl_ReceiveLobbyMessage, + XCAST(RunApplication)IDirectPlayLobbyWImpl_RunApplication, + XCAST(SendLobbyMessage)IDirectPlayLobbyWImpl_SendLobbyMessage, + XCAST(SetConnectionSettings)IDirectPlayLobbyWImpl_SetConnectionSettings, + XCAST(SetLobbyMessageEvent)IDirectPlayLobbyWImpl_SetLobbyMessageEvent, + + IDirectPlayLobby2WImpl_CreateCompoundAddress +}; +#undef XCAST + +/* Direct Play Lobby 3 (ascii) Virtual Table for methods */ + +/* Note: Hack so we can reuse the old functions without compiler warnings */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlayLobby3AVT.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static const IDirectPlayLobby3Vtbl directPlayLobby3AVT = +{ + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, + + XCAST(Connect)IDirectPlayLobbyAImpl_Connect, + XCAST(CreateAddress)IDirectPlayLobbyAImpl_CreateAddress, + XCAST(EnumAddress)IDirectPlayLobbyAImpl_EnumAddress, + XCAST(EnumAddressTypes)IDirectPlayLobbyAImpl_EnumAddressTypes, + XCAST(EnumLocalApplications)IDirectPlayLobbyAImpl_EnumLocalApplications, + XCAST(GetConnectionSettings)IDirectPlayLobbyAImpl_GetConnectionSettings, + XCAST(ReceiveLobbyMessage)IDirectPlayLobbyAImpl_ReceiveLobbyMessage, + XCAST(RunApplication)IDirectPlayLobbyAImpl_RunApplication, + XCAST(SendLobbyMessage)IDirectPlayLobbyAImpl_SendLobbyMessage, + XCAST(SetConnectionSettings)IDirectPlayLobbyAImpl_SetConnectionSettings, + XCAST(SetLobbyMessageEvent)IDirectPlayLobbyAImpl_SetLobbyMessageEvent, + + XCAST(CreateCompoundAddress)IDirectPlayLobby2AImpl_CreateCompoundAddress, + + IDirectPlayLobby3AImpl_ConnectEx, + IDirectPlayLobby3AImpl_RegisterApplication, + IDirectPlayLobby3AImpl_UnregisterApplication, + IDirectPlayLobby3AImpl_WaitForConnectionSettings +}; +#undef XCAST + +/* Direct Play Lobby 3 (unicode) Virtual Table for methods */ + +/* Note: Hack so we can reuse the old functions without compiler warnings */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(directPlayLobby3WVT.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static const IDirectPlayLobby3Vtbl directPlayLobby3WVT = +{ + XCAST(QueryInterface)DPL_QueryInterface, + XCAST(AddRef)DPL_AddRef, + XCAST(Release)DPL_Release, + + XCAST(Connect)IDirectPlayLobbyWImpl_Connect, + XCAST(CreateAddress)IDirectPlayLobbyWImpl_CreateAddress, + XCAST(EnumAddress)IDirectPlayLobbyWImpl_EnumAddress, + XCAST(EnumAddressTypes)IDirectPlayLobbyWImpl_EnumAddressTypes, + XCAST(EnumLocalApplications)IDirectPlayLobbyWImpl_EnumLocalApplications, + XCAST(GetConnectionSettings)IDirectPlayLobbyWImpl_GetConnectionSettings, + XCAST(ReceiveLobbyMessage)IDirectPlayLobbyWImpl_ReceiveLobbyMessage, + XCAST(RunApplication)IDirectPlayLobbyWImpl_RunApplication, + XCAST(SendLobbyMessage)IDirectPlayLobbyWImpl_SendLobbyMessage, + XCAST(SetConnectionSettings)IDirectPlayLobbyWImpl_SetConnectionSettings, + XCAST(SetLobbyMessageEvent)IDirectPlayLobbyWImpl_SetLobbyMessageEvent, + + XCAST(CreateCompoundAddress)IDirectPlayLobby2WImpl_CreateCompoundAddress, + + IDirectPlayLobby3WImpl_ConnectEx, + IDirectPlayLobby3WImpl_RegisterApplication, + IDirectPlayLobby3WImpl_UnregisterApplication, + IDirectPlayLobby3WImpl_WaitForConnectionSettings +}; +#undef XCAST + + +/********************************************************* + * + * Direct Play Lobby Interface Implementation + * + *********************************************************/ + +/*************************************************************************** + * DirectPlayLobbyCreateA (DPLAYX.4) + * + */ +HRESULT WINAPI DirectPlayLobbyCreateA( LPGUID lpGUIDDSP, + LPDIRECTPLAYLOBBYA *lplpDPL, + IUnknown *lpUnk, + LPVOID lpData, + DWORD dwDataSize ) +{ + TRACE("lpGUIDDSP=%p lplpDPL=%p lpUnk=%p lpData=%p dwDataSize=%08lx\n", + lpGUIDDSP,lplpDPL,lpUnk,lpData,dwDataSize); + + /* Parameter Check: lpGUIDSP, lpUnk & lpData must be NULL. dwDataSize must + * equal 0. These fields are mostly for future expansion. + */ + if ( lpGUIDDSP || lpData || dwDataSize ) + { + *lplpDPL = NULL; + return DPERR_INVALIDPARAMS; + } + + if( lpUnk ) + { + *lplpDPL = NULL; + ERR("Bad parameters!\n" ); + return CLASS_E_NOAGGREGATION; + } + + return DPL_CreateInterface( &IID_IDirectPlayLobbyA, (void**)lplpDPL ); +} + +/*************************************************************************** + * DirectPlayLobbyCreateW (DPLAYX.5) + * + */ +HRESULT WINAPI DirectPlayLobbyCreateW( LPGUID lpGUIDDSP, + LPDIRECTPLAYLOBBY *lplpDPL, + IUnknown *lpUnk, + LPVOID lpData, + DWORD dwDataSize ) +{ + TRACE("lpGUIDDSP=%p lplpDPL=%p lpUnk=%p lpData=%p dwDataSize=%08lx\n", + lpGUIDDSP,lplpDPL,lpUnk,lpData,dwDataSize); + + /* Parameter Check: lpGUIDSP, lpUnk & lpData must be NULL. dwDataSize must + * equal 0. These fields are mostly for future expansion. + */ + if ( lpGUIDDSP || lpData || dwDataSize ) + { + *lplpDPL = NULL; + ERR("Bad parameters!\n" ); + return DPERR_INVALIDPARAMS; + } + + if( lpUnk ) + { + *lplpDPL = NULL; + ERR("Bad parameters!\n" ); + return CLASS_E_NOAGGREGATION; + } + + return DPL_CreateInterface( &IID_IDirectPlayLobby, (void**)lplpDPL ); +} diff --git a/reactos/lib/dplayx/lobbysp.c b/reactos/lib/dplayx/lobbysp.c new file mode 100644 index 00000000000..261af2d597e --- /dev/null +++ b/reactos/lib/dplayx/lobbysp.c @@ -0,0 +1,462 @@ +/* This contains the implementation of the Lobby Service + * Providers interface required to communicate with Direct Play + * + * Copyright 2001 Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "winerror.h" +#include "wine/debug.h" + +#include "lobbysp.h" +#include "dplay_global.h" +#include "dpinit.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +/* Prototypes */ +static BOOL DPLSP_CreateIUnknown( LPVOID lpSP ); +static BOOL DPLSP_DestroyIUnknown( LPVOID lpSP ); +static BOOL DPLSP_CreateDPLobbySP( LPVOID lpSP, IDirectPlay2Impl* dp ); +static BOOL DPLSP_DestroyDPLobbySP( LPVOID lpSP ); + + +/* Predefine the interface */ +typedef struct IDPLobbySPImpl IDPLobbySPImpl; + +typedef struct tagDPLobbySPIUnknownData +{ + LONG ulObjRef; + CRITICAL_SECTION DPLSP_lock; +} DPLobbySPIUnknownData; + +typedef struct tagDPLobbySPData +{ + IDirectPlay2Impl* dplay; +} DPLobbySPData; + +#define DPLSP_IMPL_FIELDS \ + LONG ulInterfaceRef; \ + DPLobbySPIUnknownData* unk; \ + DPLobbySPData* sp; + +struct IDPLobbySPImpl +{ + const IDPLobbySPVtbl *lpVtbl; + DPLSP_IMPL_FIELDS +}; + +/* Forward declaration of virtual tables */ +static const IDPLobbySPVtbl dpLobbySPVT; + +HRESULT DPLSP_CreateInterface( REFIID riid, LPVOID* ppvObj, IDirectPlay2Impl* dp ) +{ + TRACE( " for %s\n", debugstr_guid( riid ) ); + + *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( IDPLobbySPImpl ) ); + + if( *ppvObj == NULL ) + { + return DPERR_OUTOFMEMORY; + } + + if( IsEqualGUID( &IID_IDPLobbySP, riid ) ) + { + IDPLobbySPImpl *This = (IDPLobbySPImpl *)*ppvObj; + This->lpVtbl = &dpLobbySPVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + return E_NOINTERFACE; + } + + /* Initialize it */ + if( DPLSP_CreateIUnknown( *ppvObj ) && + DPLSP_CreateDPLobbySP( *ppvObj, dp ) + ) + { + IDPLobbySP_AddRef( (LPDPLOBBYSP)*ppvObj ); + return S_OK; + } + + /* Initialize failed, destroy it */ + DPLSP_DestroyDPLobbySP( *ppvObj ); + DPLSP_DestroyIUnknown( *ppvObj ); + + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + return DPERR_NOMEMORY; +} + +static BOOL DPLSP_CreateIUnknown( LPVOID lpSP ) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)lpSP; + + This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) ); + + if ( This->unk == NULL ) + { + return FALSE; + } + + InitializeCriticalSection( &This->unk->DPLSP_lock ); + + return TRUE; +} + +static BOOL DPLSP_DestroyIUnknown( LPVOID lpSP ) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)lpSP; + + DeleteCriticalSection( &This->unk->DPLSP_lock ); + HeapFree( GetProcessHeap(), 0, This->unk ); + + return TRUE; +} + +static BOOL DPLSP_CreateDPLobbySP( LPVOID lpSP, IDirectPlay2Impl* dp ) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)lpSP; + + This->sp = 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. + * + * FIXME: This is a kludge to get around a problem where a queryinterface + * is used to get a new interface and then is closed. We will then + * reference garbage. However, with this we will never deallocate + * the interface we store. The correct fix is to require all + * DP internal interfaces to use the This->dp2 interface which + * should be changed to This->dp + */ + IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp ); + + + return TRUE; +} + +static BOOL DPLSP_DestroyDPLobbySP( LPVOID lpSP ) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)lpSP; + + HeapFree( GetProcessHeap(), 0, This->sp ); + + return TRUE; +} + +static +HRESULT WINAPI DPLSP_QueryInterface +( LPDPLOBBYSP iface, + REFIID riid, + LPVOID* ppvObj +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj ); + + *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof( *This ) ); + + if( *ppvObj == NULL ) + { + return DPERR_OUTOFMEMORY; + } + + CopyMemory( *ppvObj, This, sizeof( *This ) ); + (*(IDPLobbySPImpl**)ppvObj)->ulInterfaceRef = 0; + + if( IsEqualGUID( &IID_IDPLobbySP, riid ) ) + { + IDPLobbySPImpl *This = (IDPLobbySPImpl *)*ppvObj; + This->lpVtbl = &dpLobbySPVT; + } + else + { + /* Unsupported interface */ + HeapFree( GetProcessHeap(), 0, *ppvObj ); + *ppvObj = NULL; + + return E_NOINTERFACE; + } + + IDPLobbySP_AddRef( (LPDPLOBBYSP)*ppvObj ); + + return S_OK; +} + +static +ULONG WINAPI DPLSP_AddRef +( LPDPLOBBYSP iface ) +{ + ULONG ulInterfaceRefCount, ulObjRefCount; + IDPLobbySPImpl *This = (IDPLobbySPImpl *)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 DPLSP_Release +( LPDPLOBBYSP iface ) +{ + ULONG ulInterfaceRefCount, ulObjRefCount; + IDPLobbySPImpl *This = (IDPLobbySPImpl *)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 ) + { + DPLSP_DestroyDPLobbySP( This ); + DPLSP_DestroyIUnknown( This ); + } + + if( ulInterfaceRefCount == 0 ) + { + HeapFree( GetProcessHeap(), 0, This ); + } + + return ulInterfaceRefCount; +} + +static +HRESULT WINAPI IDPLobbySPImpl_AddGroupToGroup +( LPDPLOBBYSP iface, + LPSPDATA_ADDREMOTEGROUPTOGROUP argtg +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, argtg ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_AddPlayerToGroup +( LPDPLOBBYSP iface, + LPSPDATA_ADDREMOTEPLAYERTOGROUP arptg +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, arptg ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_CreateGroup +( LPDPLOBBYSP iface, + LPSPDATA_CREATEREMOTEGROUP crg +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, crg ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_CreateGroupInGroup +( LPDPLOBBYSP iface, + LPSPDATA_CREATEREMOTEGROUPINGROUP crgig +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, crgig ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_DeleteGroupFromGroup +( LPDPLOBBYSP iface, + LPSPDATA_DELETEREMOTEGROUPFROMGROUP drgfg +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, drgfg ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_DeletePlayerFromGroup +( LPDPLOBBYSP iface, + LPSPDATA_DELETEREMOTEPLAYERFROMGROUP drpfg +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, drpfg ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_DestroyGroup +( LPDPLOBBYSP iface, + LPSPDATA_DESTROYREMOTEGROUP drg +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, drg ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_EnumSessionsResponse +( LPDPLOBBYSP iface, + LPSPDATA_ENUMSESSIONSRESPONSE er +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, er ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_GetSPDataPointer +( LPDPLOBBYSP iface, + LPVOID* lplpData +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, lplpData ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_HandleMessage +( LPDPLOBBYSP iface, + LPSPDATA_HANDLEMESSAGE hm +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, hm ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_SendChatMessage +( LPDPLOBBYSP iface, + LPSPDATA_CHATMESSAGE cm +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, cm ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_SetGroupName +( LPDPLOBBYSP iface, + LPSPDATA_SETREMOTEGROUPNAME srgn +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, srgn ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_SetPlayerName +( LPDPLOBBYSP iface, + LPSPDATA_SETREMOTEPLAYERNAME srpn +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, srpn ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_SetSessionDesc +( LPDPLOBBYSP iface, + LPSPDATA_SETSESSIONDESC ssd +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, ssd ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_SetSPDataPointer +( LPDPLOBBYSP iface, + LPVOID lpData +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, lpData ); + return DP_OK; +} + +static +HRESULT WINAPI IDPLobbySPImpl_StartSession +( LPDPLOBBYSP iface, + LPSPDATA_STARTSESSIONCOMMAND ssc +) +{ + IDPLobbySPImpl *This = (IDPLobbySPImpl *)iface; + FIXME( "(%p)->(%p):stub\n", This, ssc ); + return DP_OK; +} + + +static const IDPLobbySPVtbl dpLobbySPVT = +{ + + DPLSP_QueryInterface, + DPLSP_AddRef, + DPLSP_Release, + + IDPLobbySPImpl_AddGroupToGroup, + IDPLobbySPImpl_AddPlayerToGroup, + IDPLobbySPImpl_CreateGroup, + IDPLobbySPImpl_CreateGroupInGroup, + IDPLobbySPImpl_DeleteGroupFromGroup, + IDPLobbySPImpl_DeletePlayerFromGroup, + IDPLobbySPImpl_DestroyGroup, + IDPLobbySPImpl_EnumSessionsResponse, + IDPLobbySPImpl_GetSPDataPointer, + IDPLobbySPImpl_HandleMessage, + IDPLobbySPImpl_SendChatMessage, + IDPLobbySPImpl_SetGroupName, + IDPLobbySPImpl_SetPlayerName, + IDPLobbySPImpl_SetSessionDesc, + IDPLobbySPImpl_SetSPDataPointer, + IDPLobbySPImpl_StartSession + +}; diff --git a/reactos/lib/dplayx/lobbysp.h b/reactos/lib/dplayx/lobbysp.h new file mode 100644 index 00000000000..50ed70499e6 --- /dev/null +++ b/reactos/lib/dplayx/lobbysp.h @@ -0,0 +1,520 @@ +/* + * Copyright 2001 Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_LOBBY_SP_H +#define __WINE_LOBBY_SP_H + +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "dplobby.h" + +/* GUID for IDPLobbySP {5A4E5A20-2CED-11d0-A889-00A0C905433C} */ +DEFINE_GUID(IID_IDPLobbySP, 0x5a4e5a20, 0x2ced, 0x11d0, 0xa8, 0x89, 0x0, 0xa0, 0xc9, 0x5, 0x43, 0x3c); +typedef struct IDPLobbySP *LPDPLOBBYSP; + +/* For SP. Top 16 bits is dplay, bottom 16 is SP */ +#define DPLSP_MAJORVERSION 0x00050000 + +typedef struct SPDATA_ADDGROUPTOGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwParentID; + DWORD dwGroupID; +} SPDATA_ADDGROUPTOGROUP, *LPSPDATA_ADDGROUPTOGROUP; + +typedef struct SPDATA_ADDPLAYERTOGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + DWORD dwPlayerID; +} SPDATA_ADDPLAYERTOGROUP, *LPSPDATA_ADDPLAYERTOGROUP; + +typedef struct SPDATA_ADDREMOTEGROUPTOGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwAnchorID; + DWORD dwGroupID; + DWORD dwParentID; + LPDPNAME lpName; + DWORD dwGroupFlags; +} SPDATA_ADDREMOTEGROUPTOGROUP, *LPSPDATA_ADDREMOTEGROUPTOGROUP; + +typedef struct SPDATA_ADDREMOTEPLAYERTOGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + DWORD dwPlayerID; + DWORD dwPlayerFlags; + LPDPNAME lpName; +} SPDATA_ADDREMOTEPLAYERTOGROUP, *LPSPDATA_ADDREMOTEPLAYERTOGROUP; + +typedef struct SPDATA_BUILDPARENTALHEIRARCHY +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + DWORD dwMessage; + DWORD dwParentID; +} SPDATA_BUILDPARENTALHEIRARCHY, *LPSPDATA_BUILDPARENTALHEIRARCHY; + +typedef struct SPDATA_CLOSE +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; +} SPDATA_CLOSE, *LPSPDATA_CLOSE; + +typedef struct SPDATA_CREATEGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + LPDPNAME lpName; + LPVOID lpData; + DWORD dwDataSize; + DWORD dwFlags; +} SPDATA_CREATEGROUP, *LPSPDATA_CREATEGROUP; + +typedef struct SPDATA_CREATEGROUPINGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwParentID; + DWORD dwGroupID; + LPDPNAME lpName; + LPVOID lpData; + DWORD dwDataSize; + DWORD dwFlags; +} SPDATA_CREATEGROUPINGROUP, *LPSPDATA_CREATEGROUPINGROUP; + +typedef struct SPDATA_CREATEREMOTEGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + LPDPNAME lpName; + LPVOID lpData; + DWORD dwDataSize; + DWORD dwFlags; +} SPDATA_CREATEREMOTEGROUP, *LPSPDATA_CREATEREMOTEGROUP; + +typedef struct SPDATA_CREATEREMOTEGROUPINGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwParentID; + DWORD dwGroupID; + LPDPNAME lpName; + DWORD dwFlags; +} SPDATA_CREATEREMOTEGROUPINGROUP, *LPSPDATA_CREATEREMOTEGROUPINGROUP; + +typedef struct SPDATA_CREATEPLAYER +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwPlayerID; + LPDPNAME lpName; + LPVOID lpData; + DWORD dwDataSize; + DWORD dwFlags; +} SPDATA_CREATEPLAYER, *LPSPDATA_CREATEPLAYER; + +typedef struct SPDATA_DELETEGROUPFROMGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwParentID; + DWORD dwGroupID; +} SPDATA_DELETEGROUPFROMGROUP, *LPSPDATA_DELETEGROUPFROMGROUP; + +typedef struct SPDATA_DELETEPLAYERFROMGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + DWORD dwPlayerID; +} SPDATA_DELETEPLAYERFROMGROUP, *LPSPDATA_DELETEPLAYERFROMGROUP; + +typedef struct SPDATA_DELETEREMOTEGROUPFROMGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwParentID; + DWORD dwGroupID; +} SPDATA_DELETEREMOTEGROUPFROMGROUP, *LPSPDATA_DELETEREMOTEGROUPFROMGROUP; + +typedef struct SPDATA_DELETEREMOTEPLAYERFROMGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + DWORD dwPlayerID; +} SPDATA_DELETEREMOTEPLAYERFROMGROUP, *LPSPDATA_DELETEREMOTEPLAYERFROMGROUP; + +typedef struct SPDATA_DESTROYGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; +} SPDATA_DESTROYGROUP, *LPSPDATA_DESTROYGROUP; + +typedef struct SPDATA_DESTROYREMOTEGROUP +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; +} SPDATA_DESTROYREMOTEGROUP, *LPSPDATA_DESTROYREMOTEGROUP; + +typedef struct SPDATA_DESTROYPLAYER +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwPlayerID; +} SPDATA_DESTROYPLAYER, *LPSPDATA_DESTROYPLAYER; + +typedef struct SPDATA_ENUMSESSIONS +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + LPDPSESSIONDESC2 lpsd; + DWORD dwTimeout; + DWORD dwFlags; +} SPDATA_ENUMSESSIONS, *LPSPDATA_ENUMSESSIONS; + +typedef struct SPDATA_ENUMSESSIONSRESPONSE +{ + DWORD dwSize; + LPDPSESSIONDESC2 lpsd; +} SPDATA_ENUMSESSIONSRESPONSE, *LPSPDATA_ENUMSESSIONSRESPONSE; + +typedef struct SPDATA_GETCAPS +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwFlags; + LPDPCAPS lpcaps; +} SPDATA_GETCAPS, *LPSPDATA_GETCAPS; + +typedef struct SPDATA_GETGROUPCONNECTIONSETTINGS +{ + DWORD dwSize; + DWORD dwFlags; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + LPDWORD lpdwBufferSize; + LPVOID lpBuffer; +} SPDATA_GETGROUPCONNECTIONSETTINGS, *LPSPDATA_GETGROUPCONNECTIONSETTINGS; + +typedef struct SPDATA_GETGROUPDATA +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + LPDWORD lpdwDataSize; + LPVOID lpData; +} SPDATA_GETGROUPDATA, *LPSPDATA_GETGROUPDATA; + +typedef struct SPDATA_GETPLAYERCAPS +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwFlags; + DWORD dwPlayerID; + LPDPCAPS lpcaps; +} SPDATA_GETPLAYERCAPS, *LPSPDATA_GETPLAYERCAPS; + +typedef struct SPDATA_GETPLAYERDATA +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwPlayerID; + LPDWORD lpdwDataSize; + LPVOID lpData; +} SPDATA_GETPLAYERDATA, *LPSPDATA_GETPLAYERDATA; + +typedef struct SPDATA_HANDLEMESSAGE +{ + DWORD dwSize; + DWORD dwFromID; + DWORD dwToID; + LPVOID lpBuffer; + DWORD dwBufSize; +} SPDATA_HANDLEMESSAGE, *LPSPDATA_HANDLEMESSAGE; + +typedef struct SPDATA_OPEN +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + LPDPSESSIONDESC2 lpsd; + DWORD dwFlags; + LPCDPCREDENTIALS lpCredentials; +} SPDATA_OPEN, *LPSPDATA_OPEN; + +typedef struct SPDATA_SEND +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwFromID; + DWORD dwToID; + DWORD dwFlags; + LPVOID lpBuffer; + DWORD dwBufSize; +} SPDATA_SEND, *LPSPDATA_SEND; + +typedef struct SPDATA_CHATMESSAGE +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwFromID; + DWORD dwToID; + DWORD dwFlags; + LPDPCHAT lpChat; +} SPDATA_CHATMESSAGE, *LPSPDATA_CHATMESSAGE; + +typedef struct SPDATA_SETGROUPCONNECTIONSETTINGS +{ + DWORD dwSize; + DWORD dwFlags; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + LPDPLCONNECTION lpConn; +} SPDATA_SETGROUPCONNECTIONSETTINGS, *LPSPDATA_SETGROUPCONNECTIONSETTINGS; + +typedef struct SPDATA_SETGROUPDATA +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + LPVOID lpData; + DWORD dwDataSize; + DWORD dwFlags; +} SPDATA_SETGROUPDATA, *LPSPDATA_SETGROUPDATA; + +typedef struct SPDATA_SETGROUPNAME +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + LPDPNAME lpName; + DWORD dwFlags; +} SPDATA_SETGROUPNAME, *LPSPDATA_SETGROUPNAME; + +typedef struct SPDATA_SETREMOTEGROUPNAME +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwGroupID; + LPDPNAME lpName; + DWORD dwFlags; +} SPDATA_SETREMOTEGROUPNAME, *LPSPDATA_SETREMOTEGROUPNAME; + +typedef struct SPDATA_SETPLAYERDATA +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwPlayerID; + LPVOID lpData; + DWORD dwDataSize; + DWORD dwFlags; +} SPDATA_SETPLAYERDATA, *LPSPDATA_SETPLAYERDATA; + +typedef struct SPDATA_SETPLAYERNAME +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwPlayerID; + LPDPNAME lpName; + DWORD dwFlags; +} SPDATA_SETPLAYERNAME, *LPSPDATA_SETPLAYERNAME; + +typedef struct SPDATA_SETREMOTEPLAYERNAME +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwPlayerID; + LPDPNAME lpName; + DWORD dwFlags; +} SPDATA_SETREMOTEPLAYERNAME, *LPSPDATA_SETREMOTEPLAYERNAME; + +typedef struct SPDATA_SETSESSIONDESC +{ + DWORD dwSize; + LPDPSESSIONDESC2 lpsd; +} SPDATA_SETSESSIONDESC, *LPSPDATA_SETSESSIONDESC; + +typedef struct SPDATA_SHUTDOWN +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; +} SPDATA_SHUTDOWN, *LPSPDATA_SHUTDOWN; + +typedef struct SPDATA_STARTSESSION +{ + DWORD dwSize; + LPDPLOBBYSP lpISP; + DWORD dwFlags; + DWORD dwGroupID; +} SPDATA_STARTSESSION, *LPSPDATA_STARTSESSION; + +typedef struct SPDATA_STARTSESSIONCOMMAND +{ + DWORD dwFlags; + DWORD dwGroupID; + DWORD dwHostID; + LPDPLCONNECTION lpConn; +} SPDATA_STARTSESSIONCOMMAND, *LPSPDATA_STARTSESSIONCOMMAND; + +/* Prototypes for callbacks returned by DPLSPInit */ +typedef HRESULT (WINAPI *LPSP_ADDGROUPTOGROUP)(LPSPDATA_ADDGROUPTOGROUP); +typedef HRESULT (WINAPI *LPSP_ADDPLAYERTOGROUP)(LPSPDATA_ADDPLAYERTOGROUP); +typedef HRESULT (WINAPI *LPSP_BUILDPARENTALHEIRARCHY)(LPSPDATA_BUILDPARENTALHEIRARCHY); +typedef HRESULT (WINAPI *LPSP_CLOSE)(LPSPDATA_CLOSE); +typedef HRESULT (WINAPI *LPSP_CREATEGROUP)(LPSPDATA_CREATEGROUP); +typedef HRESULT (WINAPI *LPSP_CREATEGROUPINGROUP)(LPSPDATA_CREATEGROUPINGROUP); +typedef HRESULT (WINAPI *LPSP_CREATEPLAYER)(LPSPDATA_CREATEPLAYER); +typedef HRESULT (WINAPI *LPSP_DELETEGROUPFROMGROUP)(LPSPDATA_DELETEGROUPFROMGROUP); +typedef HRESULT (WINAPI *LPSP_DELETEPLAYERFROMGROUP)(LPSPDATA_DELETEPLAYERFROMGROUP); +typedef HRESULT (WINAPI *LPSP_DESTROYGROUP)(LPSPDATA_DESTROYGROUP); +typedef HRESULT (WINAPI *LPSP_DESTROYPLAYER)(LPSPDATA_DESTROYPLAYER); +typedef HRESULT (WINAPI *LPSP_ENUMSESSIONS)(LPSPDATA_ENUMSESSIONS); +typedef HRESULT (WINAPI *LPSP_GETCAPS)(LPSPDATA_GETCAPS); +typedef HRESULT (WINAPI *LPSP_GETGROUPCONNECTIONSETTINGS)(LPSPDATA_GETGROUPCONNECTIONSETTINGS); +typedef HRESULT (WINAPI *LPSP_GETGROUPDATA)(LPSPDATA_GETGROUPDATA); +typedef HRESULT (WINAPI *LPSP_GETPLAYERCAPS)(LPSPDATA_GETPLAYERCAPS); +typedef HRESULT (WINAPI *LPSP_GETPLAYERDATA)(LPSPDATA_GETPLAYERDATA); +typedef HRESULT (WINAPI *LPSP_HANDLEMESSAGE)(LPSPDATA_HANDLEMESSAGE); +typedef HRESULT (WINAPI *LPSP_OPEN)(LPSPDATA_OPEN); +typedef HRESULT (WINAPI *LPSP_SEND)(LPSPDATA_SEND); +typedef HRESULT (WINAPI *LPSP_SENDCHATMESSAGE)(LPSPDATA_CHATMESSAGE); +typedef HRESULT (WINAPI *LPSP_SETGROUPCONNECTIONSETTINGS)(LPSPDATA_SETGROUPCONNECTIONSETTINGS); +typedef HRESULT (WINAPI *LPSP_SETGROUPDATA)(LPSPDATA_SETGROUPDATA); +typedef HRESULT (WINAPI *LPSP_SETGROUPNAME)(LPSPDATA_SETGROUPNAME); +typedef HRESULT (WINAPI *LPSP_SETPLAYERDATA)(LPSPDATA_SETPLAYERDATA); +typedef HRESULT (WINAPI *LPSP_SETPLAYERNAME)(LPSPDATA_SETPLAYERNAME); +typedef HRESULT (WINAPI *LPSP_SHUTDOWN)(LPSPDATA_SHUTDOWN); +typedef HRESULT (WINAPI *LPSP_STARTSESSION)(LPSPDATA_STARTSESSION); + +/* Callback table for dplay to call into service provider */ +typedef struct SP_CALLBACKS +{ + DWORD dwSize; + DWORD dwFlags; + LPSP_ADDGROUPTOGROUP AddGroupToGroup; + LPSP_ADDPLAYERTOGROUP AddPlayerToGroup; + LPSP_BUILDPARENTALHEIRARCHY BuildParentalHeirarchy; + LPSP_CLOSE Close; + LPSP_CREATEGROUP CreateGroup; + LPSP_CREATEGROUPINGROUP CreateGroupInGroup; + LPSP_CREATEPLAYER CreatePlayer; + LPSP_DELETEGROUPFROMGROUP DeleteGroupFromGroup; + LPSP_DELETEPLAYERFROMGROUP DeletePlayerFromGroup; + LPSP_DESTROYGROUP DestroyGroup; + LPSP_DESTROYPLAYER DestroyPlayer; + LPSP_ENUMSESSIONS EnumSessions; + LPSP_GETCAPS GetCaps; + LPSP_GETGROUPCONNECTIONSETTINGS GetGroupConnectionSettings; + LPSP_GETGROUPDATA GetGroupData; + LPSP_GETPLAYERCAPS GetPlayerCaps; + LPSP_GETPLAYERDATA GetPlayerData; + LPSP_OPEN Open; + LPSP_SEND Send; + LPSP_SENDCHATMESSAGE SendChatMessage; + LPSP_SETGROUPCONNECTIONSETTINGS SetGroupConnectionSettings; + LPSP_SETGROUPDATA SetGroupData; + LPSP_SETGROUPNAME SetGroupName; + LPSP_SETPLAYERDATA SetPlayerData; + LPSP_SETPLAYERNAME SetPlayerName; + LPSP_SHUTDOWN Shutdown; + LPSP_STARTSESSION StartSession; +} SP_CALLBACKS, *LPSP_CALLBACKS; + +typedef struct SPDATA_INIT +{ + LPSP_CALLBACKS lpCB; + DWORD dwSPVersion; + LPDPLOBBYSP lpISP; + LPDPADDRESS lpAddress; +} SPDATA_INIT, *LPSPDATA_INIT; + +typedef HRESULT (WINAPI *LPSP_INIT)(LPSPDATA_INIT); +HRESULT WINAPI DPLSPInit(LPSPDATA_INIT); + +/* Define the COM interface */ +#define INTERFACE IDPLobbySP +DECLARE_INTERFACE_(IDPLobbySP,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDPLobbySP methods ***/ + STDMETHOD(AddGroupToGroup)(THIS_ LPSPDATA_ADDREMOTEGROUPTOGROUP argtg ) PURE; + STDMETHOD(AddPlayerToGroup)(THIS_ LPSPDATA_ADDREMOTEPLAYERTOGROUP arptg ) PURE; + STDMETHOD(CreateGroup)(THIS_ LPSPDATA_CREATEREMOTEGROUP crg ) PURE; + STDMETHOD(CreateGroupInGroup)(THIS_ LPSPDATA_CREATEREMOTEGROUPINGROUP crgig ) PURE; + STDMETHOD(DeleteGroupFromGroup)(THIS_ LPSPDATA_DELETEREMOTEGROUPFROMGROUP drgfg ) PURE; + STDMETHOD(DeletePlayerFromGroup)(THIS_ LPSPDATA_DELETEREMOTEPLAYERFROMGROUP drpfg ) PURE; + STDMETHOD(DestroyGroup)(THIS_ LPSPDATA_DESTROYREMOTEGROUP drg ) PURE; + STDMETHOD(EnumSessionsResponse)(THIS_ LPSPDATA_ENUMSESSIONSRESPONSE er ) PURE; + STDMETHOD(GetSPDataPointer)(THIS_ LPVOID * lplpData ) PURE; + STDMETHOD(HandleMessage)(THIS_ LPSPDATA_HANDLEMESSAGE hm ) PURE; + STDMETHOD(SendChatMessage)(THIS_ LPSPDATA_CHATMESSAGE cm ) PURE; + STDMETHOD(SetGroupName)(THIS_ LPSPDATA_SETREMOTEGROUPNAME srgn ) PURE; + STDMETHOD(SetPlayerName)(THIS_ LPSPDATA_SETREMOTEPLAYERNAME srpn ) PURE; + STDMETHOD(SetSessionDesc)(THIS_ LPSPDATA_SETSESSIONDESC ssd ) PURE; + STDMETHOD(SetSPDataPointer)(THIS_ LPVOID lpData ) PURE; + STDMETHOD(StartSession)(THIS_ LPSPDATA_STARTSESSIONCOMMAND ssc ) PURE; +}; +#undef INTERFACE + +#if !defined (__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDPLobbySP_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDPLobbySP_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDPLobbySP_Release(p) (p)->lpVtbl->Release(p) + +/*** IDPLobbySP methods ***/ +#define IDPLobbySP_AddGroupToGroup(p,a) (p)->lpVtbl->AddGroupToGroup(p,a) +#define IDPLobbySP_AddPlayerToGroup(p,a) (p)->lpVtbl->AddPlayerToGroup(p,a) +#define IDPLobbySP_CreateGroup(p,a) (p)->lpVtbl->CreateGroup(p,a) +#define IDPLobbySP_CreateGroupInGroup(p,a) (p)->lpVtbl->CreateGroupInGroup(p,a) +#define IDPLobbySP_DeleteGroupFromGroup(p,a) (p)->lpVtbl->DeleteGroupFromGroup(p,a) +#define IDPLobbySP_DeletePlayerFromGroup(p,a) (p)->lpVtbl->DeletePlayerFromGroup(p,a) +#define IDPLobbySP_DestroyGroup(p,a) (p)->lpVtbl->DestroyGroup(p,a) +#define IDPLobbySP_EnumSessionsResponse(p,a) (p)->lpVtbl->EnumSessionsResponse(p,a) +#define IDPLobbySP_GetSPDataPointer(p,a) (p)->lpVtbl->GetSPDataPointer(p,a) +#define IDPLobbySP_HandleMessage(p,a) (p)->lpVtbl->HandleMessage(p,a) +#define IDPLobbySP_SetGroupName(p,a) (p)->lpVtbl->SetGroupName(p,a) +#define IDPLobbySP_SetPlayerName(p,a) (p)->lpVtbl->SetPlayerName(p,a) +#define IDPLobbySP_SetSessionDesc(p,a) (p)->lpVtbl->SetSessionDesc(p,a) +#define IDPLobbySP_StartSession(p,a) (p)->lpVtbl->StartSession(p,a) +#define IDPLobbySP_SetSPDataPointer(p,a) (p)->lpVtbl->SetSPDataPointer(p,a) +#endif + +/* This variable is exported from the DLL at ordinal 6 to be accessed by the + * SP directly. This is the same variable that the DP SP will use. + */ +extern DWORD gdwDPlaySPRefCount; + +#endif diff --git a/reactos/lib/dplayx/name_server.c b/reactos/lib/dplayx/name_server.c new file mode 100644 index 00000000000..7548b18f11a --- /dev/null +++ b/reactos/lib/dplayx/name_server.c @@ -0,0 +1,425 @@ +/* DPLAYX.DLL name server implementation + * + * Copyright 2000-2001 - Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* NOTE: Methods with the NS_ prefix are name server methods */ + +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "wine/unicode.h" +#include "wine/debug.h" +#include "mmsystem.h" + +#include "dplayx_global.h" +#include "name_server.h" +#include "dplaysp.h" +#include "dplayx_messages.h" +#include "dplayx_queue.h" + +/* FIXME: Need to create a crit section, store and use it */ + +WINE_DEFAULT_DEBUG_CHANNEL(dplay); + +/* NS specific structures */ +struct NSCacheData +{ + DPQ_ENTRY(NSCacheData) next; + + DWORD dwTime; /* Time at which data was last known valid */ + LPDPSESSIONDESC2 data; + + LPVOID lpNSAddrHdr; + +}; +typedef struct NSCacheData NSCacheData, *lpNSCacheData; + +struct NSCache +{ + lpNSCacheData present; /* keep track of what is to be looked at when walking */ + + DPQ_HEAD(NSCacheData) first; + + BOOL bNsIsLocal; + LPVOID lpLocalAddrHdr; /* FIXME: Not yet used */ + LPVOID lpRemoteAddrHdr; /* FIXME: Not yet used */ +}; +typedef struct NSCache NSCache, *lpNSCache; + +/* Function prototypes */ +DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData ); + +/* Name Server functions + * --------------------- + */ +void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd, LPVOID lpNSInfo ) +{ +#if 0 + /* FIXME: Remove this method? */ + DPLAYX_SetLocalSession( lpsd ); +#endif + lpNSCache lpCache = (lpNSCache)lpNSInfo; + + lpCache->bNsIsLocal = TRUE; +} + +void NS_SetRemoteComputerAsNameServer( LPCDPSESSIONDESC2 lpsd, LPVOID lpNSInfo ) +{ + lpNSCache lpCache = (lpNSCache)lpNSInfo; + + lpCache->bNsIsLocal = FALSE; +} + +static DPQ_DECL_COMPARECB( cbUglyPig, GUID ) +{ + return IsEqualGUID( elem1, elem2 ); +} + +/* Store the given NS remote address for future reference */ +/* FIXME: LPDPMSG_ENUMSESSIONSREPLY should be const */ +void NS_AddRemoteComputerAsNameServer( LPCVOID lpcNSAddrHdr, + DWORD dwHdrSize, + LPDPMSG_ENUMSESSIONSREPLY lpMsg, + LPVOID lpNSInfo ) +{ + DWORD len; + lpNSCache lpCache = (lpNSCache)lpNSInfo; + lpNSCacheData lpCacheNode; + + TRACE( "%p, %p, %p\n", lpcNSAddrHdr, lpMsg, lpNSInfo ); + + /* See if we can find this session. If we can, remove it as it's a dup */ + DPQ_REMOVE_ENTRY_CB( lpCache->first, next, data->guidInstance, cbUglyPig, + lpMsg->sd.guidInstance, lpCacheNode ); + + if( lpCacheNode != NULL ) + { + TRACE( "Duplicate session entry for %s removed - updated version kept\n", + debugstr_guid( &lpCacheNode->data->guidInstance ) ); + cbDeleteNSNodeFromHeap( lpCacheNode ); + } + + /* Add this to the list */ + lpCacheNode = 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, lpcNSAddrHdr, dwHdrSize ); + + lpCacheNode->data = 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 ) ); + len = WideCharToMultiByte( CP_ACP, 0, (LPWSTR)(lpMsg+1), -1, NULL, 0, NULL, NULL ); + if ((lpCacheNode->data->lpszSessionNameA = HeapAlloc( GetProcessHeap(), 0, len ))) + { + WideCharToMultiByte( CP_ACP, 0, (LPWSTR)(lpMsg+1), -1, + lpCacheNode->data->lpszSessionNameA, len, NULL, NULL ); + } + + lpCacheNode->dwTime = timeGetTime(); + + DPQ_INSERT(lpCache->first, lpCacheNode, next ); + + lpCache->present = lpCacheNode; + + /* Use this message as an opportunity 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? + * This is going to have to go into dplay somehow. Perhaps it + * comes back with app server id for the join command! Oh...that + * must be it. That would make this method obsolete once that's + * in place. + */ +#if 1 + return lpCache->first.lpQHFirst->lpNSAddrHdr; +#else + /* FIXME: Should convert over to this */ + return lpCache->bNsIsLocal ? lpCache->lpLocalAddrHdr + : lpCache->lpRemoteAddrHdr; +#endif +} + +/* Get the magic number associated with the Name Server */ +DWORD NS_GetNsMagic( LPVOID lpNSInfo ) +{ + LPDWORD lpHdrInfo = (LPDWORD)NS_GetNSAddr( lpNSInfo ); + + return lpHdrInfo[1]; +} + +/* Get the magic number associated with the non NS end */ +DWORD NS_GetOtherMagic( LPVOID lpNSInfo ) +{ + lpNSCache lpCache = (lpNSCache)lpNSInfo; + + return ((LPDWORD)lpCache->lpLocalAddrHdr)[1]; +} + +void NS_SetLocalAddr( LPVOID lpNSInfo, LPCVOID lpHdr, DWORD dwHdrSize ) +{ + lpNSCache lpCache = (lpNSCache)lpNSInfo; + + lpCache->lpLocalAddrHdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwHdrSize ); + + CopyMemory( lpCache->lpLocalAddrHdr, lpHdr, dwHdrSize ); +} + +/* This function is responsible for sending a request for all other known + nameservers to send us what sessions they have registered locally + */ +HRESULT NS_SendSessionRequestBroadcast( LPCGUID lpcGuid, + DWORD dwFlags, + LPSPINITDATA lpSpData ) + +{ + DPSP_ENUMSESSIONSDATA data; + LPDPMSG_ENUMSESSIONSREQUEST lpMsg; + + TRACE( "enumerating for guid %s\n", debugstr_guid( lpcGuid ) ); + + /* Get the SP to deal with sending the EnumSessions request */ + FIXME( ": not all data fields are correct\n" ); + + 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; + + + lpMsg = (LPDPMSG_ENUMSESSIONSREQUEST)(((BYTE*)data.lpMessage)+lpSpData->dwSPHeaderSize); + + /* Setup EnumSession request 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 ); +} + +/* Delete a name server node which has been allocated on the heap */ +DPQ_DECL_DELETECB( cbDeleteNSNodeFromHeap, lpNSCacheData ) +{ + /* NOTE: This proc doesn't deal with the walking pointer */ + + /* FIXME: Memory leak on data (contained ptrs) */ + HeapFree( GetProcessHeap(), 0, elem->data ); + HeapFree( GetProcessHeap(), 0, elem->lpNSAddrHdr ); + HeapFree( GetProcessHeap(), 0, elem ); +} + +/* Render all data in a session cache invalid */ +void NS_InvalidateSessionCache( LPVOID lpNSInfo ) +{ + lpNSCache lpCache = (lpNSCache)lpNSInfo; + + if( lpCache == NULL ) + { + ERR( ": invalidate nonexistent cache\n" ); + return; + } + + DPQ_DELETEQ( lpCache->first, next, lpNSCacheData, cbDeleteNSNodeFromHeap ); + + /* NULL out the walking pointer */ + lpCache->present = NULL; + + lpCache->bNsIsLocal = FALSE; + +} + +/* Create and initialize a session cache */ +BOOL NS_InitializeSessionCache( LPVOID* lplpNSInfo ) +{ + lpNSCache lpCache = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpCache ) ); + + *lplpNSInfo = lpCache; + + if( lpCache == NULL ) + { + return FALSE; + } + + DPQ_INIT(lpCache->first); + lpCache->present = NULL; + + lpCache->bNsIsLocal = FALSE; + + return TRUE; +} + +/* Delete a session cache */ +void NS_DeleteSessionCache( LPVOID lpNSInfo ) +{ + NS_InvalidateSessionCache( (lpNSCache)lpNSInfo ); +} + +/* Reinitialize the present pointer for this cache */ +void NS_ResetSessionEnumeration( LPVOID lpNSInfo ) +{ + ((lpNSCache)lpNSInfo)->present = ((lpNSCache)lpNSInfo)->first.lpQHFirst; +} + +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 ) + { + return NULL; + } + + lpSessionDesc = lpCache->present->data; + + /* Advance tracking pointer */ + 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. + */ +/* FIXME: This needs to be called by some periodic timer */ +void NS_PruneSessionCache( LPVOID lpNSInfo ) +{ + lpNSCache lpCache = lpNSInfo; + + const DWORD dwPresentTime = timeGetTime(); + const DWORD dwPrunePeriod = DPMSG_WAIT_60_SECS; /* is 60 secs enough? */ + + /* This silly little algorithm is based on the fact we keep entries in + * the queue in a time based order. It also assumes that it is not possible + * to wrap around over yourself (which is not unreasonable). + * The if statements verify if the first entry in the queue is less + * than dwPrunePeriod old depending on the "clock" roll over. + */ + for( ;; ) + { + lpNSCacheData lpFirstData; + + if( DPQ_IS_EMPTY(lpCache->first) ) + { + /* Nothing to prune */ + break; + } + + /* Deal with time in a wrap around safe manner - unsigned arithmetic. + * Check the difference in time */ + if( (dwPresentTime - (DPQ_FIRST(lpCache->first)->dwTime)) < dwPrunePeriod ) + { + /* First entry has not expired yet; don't prune */ + break; + } + + lpFirstData = DPQ_FIRST(lpCache->first); + DPQ_REMOVE( lpCache->first, DPQ_FIRST(lpCache->first), next ); + cbDeleteNSNodeFromHeap( lpFirstData ); + } + +} + +/* NAME SERVER Message stuff */ +void NS_ReplyToEnumSessionsRequest( LPCVOID lpcMsg, + LPVOID* lplpReplyData, + LPDWORD lpdwReplySize, + IDirectPlay2Impl* lpDP ) +{ + LPDPMSG_ENUMSESSIONSREPLY rmsg; + DWORD dwVariableSize; + DWORD dwVariableLen; + /* LPCDPMSG_ENUMSESSIONSREQUEST msg = (LPDPMSG_ENUMSESSIONSREQUEST)lpcMsg; */ + BOOL bAnsi = TRUE; /* FIXME: This needs to be in the DPLAY interface */ + + FIXME( ": few fixed + need to check request for response\n" ); + + if (bAnsi) + { + dwVariableLen = MultiByteToWideChar( CP_ACP, 0, + lpDP->dp2->lpSessionDesc->lpszSessionNameA, + -1, NULL, 0 ); + } + else + { + dwVariableLen = strlenW( lpDP->dp2->lpSessionDesc->lpszSessionName ) + 1; + } + + dwVariableSize = dwVariableLen * sizeof( WCHAR ); + + *lpdwReplySize = lpDP->dp2->spData.dwSPHeaderSize + + sizeof( *rmsg ) + dwVariableSize; + *lplpReplyData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + *lpdwReplySize ); + + rmsg = (LPDPMSG_ENUMSESSIONSREPLY)( (BYTE*)*lplpReplyData + + lpDP->dp2->spData.dwSPHeaderSize); + + 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 ) + { + MultiByteToWideChar( CP_ACP, 0, lpDP->dp2->lpSessionDesc->lpszSessionNameA, -1, + (LPWSTR)(rmsg+1), dwVariableLen ); + } + else + { + strcpyW( (LPWSTR)(rmsg+1), lpDP->dp2->lpSessionDesc->lpszSessionName ); + } +} diff --git a/reactos/lib/dplayx/name_server.h b/reactos/lib/dplayx/name_server.h new file mode 100644 index 00000000000..fc3f0eb2768 --- /dev/null +++ b/reactos/lib/dplayx/name_server.h @@ -0,0 +1,61 @@ +/* + * Copyright 2000 Peter Hunnisett + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_DPLAYX_NAMESERVER +#define __WINE_DPLAYX_NAMESERVER + +#include + +#include "windef.h" +#include "winbase.h" +#include "dplay.h" +#include "dplaysp.h" +#include "dplayx_messages.h" +#include "dplay_global.h" + +void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd, LPVOID lpNSInfo ); +void NS_SetRemoteComputerAsNameServer( LPCDPSESSIONDESC2 lpsd, LPVOID lpNSInfo ); +void NS_AddRemoteComputerAsNameServer( LPCVOID lpNSAddrHdr, + DWORD dwHdrSize, + LPDPMSG_ENUMSESSIONSREPLY lpMsg, + LPVOID lpNSInfo ); +LPVOID NS_GetNSAddr( LPVOID lpNSInfo ); +DWORD NS_GetNsMagic( LPVOID lpNSInfo ); +DWORD NS_GetOtherMagic( LPVOID lpNSInfo ); +void NS_SetLocalAddr( LPVOID lpNSInfo, LPCVOID lpHdr, DWORD dwHdrSize ); + +void NS_ReplyToEnumSessionsRequest( LPCVOID lpcMsg, + LPVOID* lplpReplyData, + LPDWORD lpdwReplySize, + 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/reactos/lib/dplayx/regsvr.c b/reactos/lib/dplayx/regsvr.c new file mode 100644 index 00000000000..abaa33dd813 --- /dev/null +++ b/reactos/lib/dplayx/regsvr.c @@ -0,0 +1,556 @@ +/* + * self-registerable dll functions for dplayx.dll + * + * Copyright (C) 2003 John K. Hohm + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "winerror.h" + +#include "dplay.h" +#include "dplobby.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dplayx); + +/* + * Near the bottom of this file are the exported DllRegisterServer and + * DllUnregisterServer, which make all this worthwhile. + */ + +/*********************************************************************** + * interface for self-registering + */ +struct regsvr_interface +{ + IID const *iid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + IID const *base_iid; /* can be NULL to omit */ + int num_methods; /* can be <0 to omit */ + CLSID const *ps_clsid; /* can be NULL to omit */ + CLSID const *ps_clsid32; /* can be NULL to omit */ +}; + +static HRESULT register_interfaces(struct regsvr_interface const *list); +static HRESULT unregister_interfaces(struct regsvr_interface const *list); + +struct regsvr_coclass +{ + CLSID const *clsid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + LPCSTR ips; /* can be NULL to omit */ + LPCSTR ips32; /* can be NULL to omit */ + LPCSTR ips32_tmodel; /* can be NULL to omit */ + LPCSTR progid; /* can be NULL to omit */ + LPCSTR viprogid; /* can be NULL to omit */ + LPCSTR progid_extra; /* can be NULL to omit */ +}; + +static HRESULT register_coclasses(struct regsvr_coclass const *list); +static HRESULT unregister_coclasses(struct regsvr_coclass const *list); + +/*********************************************************************** + * static string constants + */ +static WCHAR const interface_keyname[10] = { + 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; +static WCHAR const base_ifa_keyname[14] = { + 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', + 'e', 0 }; +static WCHAR const num_methods_keyname[11] = { + 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; +static WCHAR const ps_clsid_keyname[15] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', 0 }; +static WCHAR const ps_clsid32_keyname[17] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', '3', '2', 0 }; +static WCHAR const clsid_keyname[6] = { + 'C', 'L', 'S', 'I', 'D', 0 }; +static WCHAR const curver_keyname[7] = { + 'C', 'u', 'r', 'V', 'e', 'r', 0 }; +static WCHAR const ips_keyname[13] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + 0 }; +static WCHAR const ips32_keyname[15] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + '3', '2', 0 }; +static WCHAR const progid_keyname[7] = { + 'P', 'r', 'o', 'g', 'I', 'D', 0 }; +static WCHAR const viprogid_keyname[25] = { + 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', + 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', + 0 }; +static char const tmodel_valuename[] = "ThreadingModel"; + +/*********************************************************************** + * static helper functions + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); +static LONG register_key_defvalueW(HKEY base, WCHAR const *name, + WCHAR const *value); +static LONG register_key_defvalueA(HKEY base, WCHAR const *name, + char const *value); +static LONG register_progid(WCHAR const *clsid, + char const *progid, char const *curver_progid, + char const *name, char const *extra); +static LONG recursive_delete_key(HKEY key); +static LONG recursive_delete_keyA(HKEY base, char const *name); +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); + +/*********************************************************************** + * register_interfaces + */ +static HRESULT register_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + HKEY iid_key; + + StringFromGUID2(list->iid, buf, 39); + res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_interface_key; + + if (list->name) { + res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->base_iid) { + register_key_guid(iid_key, base_ifa_keyname, list->base_iid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (0 <= list->num_methods) { + static WCHAR const fmt[3] = { '%', 'd', 0 }; + HKEY key; + + res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + + wsprintfW(buf, fmt, list->num_methods); + res = RegSetValueExW(key, NULL, 0, REG_SZ, + (CONST BYTE*)buf, + (lstrlenW(buf) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid) { + register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid32) { + register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + error_close_iid_key: + RegCloseKey(iid_key); + } + +error_close_interface_key: + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_interfaces + */ +static HRESULT unregister_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, + KEY_READ | KEY_WRITE, &interface_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->iid, buf, 39); + res = recursive_delete_keyW(interface_key, buf); + } + + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * register_coclasses + */ +static HRESULT register_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + HKEY clsid_key; + + StringFromGUID2(list->clsid, buf, 39); + res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->name) { + res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips) { + res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips32) { + HKEY ips32_key; + + res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &ips32_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, + (CONST BYTE*)list->ips32, + lstrlenA(list->ips32) + 1); + if (res == ERROR_SUCCESS && list->ips32_tmodel) + res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, + (CONST BYTE*)list->ips32_tmodel, + strlen(list->ips32_tmodel) + 1); + RegCloseKey(ips32_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->progid) { + res = register_key_defvalueA(clsid_key, progid_keyname, + list->progid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->progid, NULL, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->viprogid) { + res = register_key_defvalueA(clsid_key, viprogid_keyname, + list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->viprogid, list->progid, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + error_close_clsid_key: + RegCloseKey(clsid_key); + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_coclasses + */ +static HRESULT unregister_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, + KEY_READ | KEY_WRITE, &coclass_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->clsid, buf, 39); + res = recursive_delete_keyW(coclass_key, buf); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->progid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + + if (list->viprogid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * regsvr_key_guid + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) +{ + WCHAR buf[39]; + + StringFromGUID2(guid, buf, 39); + return register_key_defvalueW(base, name, buf); +} + +/*********************************************************************** + * regsvr_key_defvalueW + */ +static LONG register_key_defvalueW( + HKEY base, + WCHAR const *name, + WCHAR const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + (lstrlenW(value) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_key_defvalueA + */ +static LONG register_key_defvalueA( + HKEY base, + WCHAR const *name, + char const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + lstrlenA(value) + 1); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_progid + */ +static LONG register_progid( + WCHAR const *clsid, + char const *progid, + char const *curver_progid, + char const *name, + char const *extra) +{ + LONG res; + HKEY progid_key; + + res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &progid_key, NULL); + if (res != ERROR_SUCCESS) return res; + + if (name) { + res = RegSetValueExA(progid_key, NULL, 0, REG_SZ, + (CONST BYTE*)name, strlen(name) + 1); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (clsid) { + res = register_key_defvalueW(progid_key, clsid_keyname, clsid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (curver_progid) { + res = register_key_defvalueA(progid_key, curver_keyname, + curver_progid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (extra) { + HKEY extra_key; + + res = RegCreateKeyExA(progid_key, extra, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &extra_key, NULL); + if (res == ERROR_SUCCESS) + RegCloseKey(extra_key); + } + +error_close_progid_key: + RegCloseKey(progid_key); + return res; +} + +/*********************************************************************** + * recursive_delete_key + */ +static LONG recursive_delete_key(HKEY key) +{ + LONG res; + WCHAR subkey_name[MAX_PATH]; + DWORD cName; + HKEY subkey; + + for (;;) { + cName = sizeof(subkey_name) / sizeof(WCHAR); + res = RegEnumKeyExW(key, 0, subkey_name, &cName, + NULL, NULL, NULL, NULL); + if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { + res = ERROR_SUCCESS; /* presumably we're done enumerating */ + break; + } + res = RegOpenKeyExW(key, subkey_name, 0, + KEY_READ | KEY_WRITE, &subkey); + if (res == ERROR_FILE_NOT_FOUND) continue; + if (res != ERROR_SUCCESS) break; + + res = recursive_delete_key(subkey); + RegCloseKey(subkey); + if (res != ERROR_SUCCESS) break; + } + + if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); + return res; +} + +/*********************************************************************** + * recursive_delete_keyA + */ +static LONG recursive_delete_keyA(HKEY base, char const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * recursive_delete_keyW + */ +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * coclass list + */ +static struct regsvr_coclass const coclass_list[] = { + { &CLSID_DirectPlay, + "DirectPlay Object", + NULL, + "dplayx.dll", + "Both" + }, + { &CLSID_DirectPlayLobby, + "DirectPlayLobby Object", + NULL, + "dplayx.dll", + "Both" + }, + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * interface list + */ + +static struct regsvr_interface const interface_list[] = { + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * DllRegisterServer (DPLAYX.@) + */ +HRESULT WINAPI DllRegisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = register_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = register_interfaces(interface_list); + return hr; +} + +/*********************************************************************** + * DllUnregisterServer (DPLAYX.@) + */ +HRESULT WINAPI DllUnregisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = unregister_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = unregister_interfaces(interface_list); + return hr; +} diff --git a/reactos/lib/dplayx/version.rc b/reactos/lib/dplayx/version.rc new file mode 100644 index 00000000000..4b0f15a06dc --- /dev/null +++ b/reactos/lib/dplayx/version.rc @@ -0,0 +1,27 @@ +/* + * Copyright 2001 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define WINE_OLESELFREGISTER +#define WINE_FILEDESCRIPTION_STR "Wine DirectPlay" +#define WINE_FILENAME_STR "dplayx.dll" +#define WINE_FILEVERSION 5,3,0,900 +#define WINE_FILEVERSION_STR "5.3.0.900" +#define WINE_PRODUCTVERSION 5,3,0,900 +#define WINE_PRODUCTVERSION_STR "5.3" + +#include "wine/wine_common_ver.rc"