[DPLAYX]
[reactos.git] / reactos / dll / directx / wine / dplayx / dplay.c
index c22dc2d..e4514bf 100644 (file)
@@ -17,6 +17,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#define COBJMACROS
 #include <config.h>
 //#include "wine/port.h"
 
@@ -34,7 +35,6 @@
 #include <wine/unicode.h>
 #include <wine/debug.h>
 
-#include "dpinit.h"
 #include "dplayx_global.h"
 #include "name_server.h"
 //#include "dplayx_queue.h"
@@ -50,156 +50,26 @@ extern HRESULT DPL_CreateCompoundAddress
 
 
 /* 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 lpPlayerList DP_FindPlayer( IDirectPlayImpl *This, DPID dpid );
 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
-static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
-                              LPVOID lpData, DWORD dwDataSize );
-
-static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, const DPID *lpid,
-                                   const DPNAME *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;
+static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid );
 
 /* Helper methods for player/group interfaces */
-static HRESULT DP_IF_DeletePlayerFromGroup
-          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
-            DPID idPlayer, BOOL bAnsi );
-static HRESULT DP_IF_CreatePlayer
-          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
-            LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
-            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_DestroyGroup
-          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
-static HRESULT DP_IF_DestroyPlayer
-          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
-static HRESULT DP_IF_EnumGroupPlayers
-          ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_EnumGroups
-          ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_EnumPlayers
-          ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_GetGroupData
-          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
-            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_GetGroupName
-          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
-            LPDWORD lpdwDataSize, BOOL bAnsi );
-static HRESULT DP_IF_GetPlayerData
-          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
-            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_GetPlayerName
-          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
-            LPDWORD lpdwDataSize, BOOL bAnsi );
-static HRESULT DP_IF_SetGroupName
-          ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
-            DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_SetPlayerData
-          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
-            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_SetPlayerName
-          ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
-            DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_AddGroupToGroup
-          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
-static HRESULT DP_IF_CreateGroup
-          ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
-            LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
-            DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_CreateGroupInGroup
-          ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
-            LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
-            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_AddPlayerToGroup
-          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
-            DPID idPlayer, BOOL bAnsi );
-static HRESULT DP_IF_DeleteGroupFromGroup
-          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
-static HRESULT DP_SetSessionDesc
-          ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
-            DWORD dwFlags, BOOL bInitial, BOOL bAnsi  );
-static HRESULT DP_SecureOpen
-          ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
-            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
-            BOOL bAnsi );
-static HRESULT 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 DP_IF_Receive
-          ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
-            DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
-static HRESULT DP_IF_GetMessageQueue
-          ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
-            LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
-static HRESULT DP_SP_SendEx
-          ( IDirectPlay2Impl* This, DWORD dwFlags,
-            LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
-            LPVOID lpContext, LPDWORD lpdwMsgID );
-static HRESULT DP_IF_SetGroupData
-          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
-            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_GetPlayerCaps
-          ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
-            DWORD dwFlags );
-static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
-static HRESULT DP_IF_CancelMessage
-          ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
-            DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
-static HRESULT DP_IF_EnumGroupsInGroup
-          ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
-static HRESULT DP_IF_GetGroupParent
-          ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
-            BOOL bAnsi );
-static HRESULT DP_IF_GetCaps
-          ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
-static HRESULT DP_IF_EnumSessions
-          ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
-            LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
-            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
-static HRESULT 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 HRESULT DP_SetSessionDesc( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpSessDesc,
+        DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
+static HRESULT DP_SP_SendEx( IDirectPlayImpl *This, DWORD dwFlags, void *lpData, DWORD dwDataSize,
+        DWORD dwPriority, DWORD dwTimeout, void *lpContext, DWORD *lpdwMsgID );
 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
                                     LPDWORD lpdwBufSize );
 
-
-
-static inline DPID DP_NextObjectId(void);
 static DPID DP_GetRemoteNextObjectId(void);
 
 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
@@ -207,15 +77,6 @@ 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 */
@@ -229,39 +90,45 @@ static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvi
 
 static LONG kludgePlayerGroupId = 1000;
 
-/* ------------------------------------------------------------------ */
-
 
-static BOOL DP_CreateIUnknown( LPVOID lpDP )
+static inline IDirectPlayImpl *impl_from_IDirectPlay( IDirectPlay *iface )
 {
-  IDirectPlay2AImpl *This = lpDP;
+    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay_iface );
+}
 
-  This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
-  if ( This->unk == NULL )
-  {
-    return FALSE;
-  }
+static inline IDirectPlayImpl *impl_from_IDirectPlay2( IDirectPlay2 *iface )
+{
+    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay2_iface );
+}
 
-  InitializeCriticalSection( &This->unk->DP_lock );
-  This->unk->DP_lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlay2AImpl*->DirectPlayIUnknownData*->DP_lock");
+static inline IDirectPlayImpl *impl_from_IDirectPlay2A( IDirectPlay2A *iface )
+{
+    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay2A_iface );
+}
 
-  return TRUE;
+static inline IDirectPlayImpl *impl_from_IDirectPlay3A( IDirectPlay3A *iface )
+{
+    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay3A_iface );
 }
 
-static BOOL DP_DestroyIUnknown( LPVOID lpDP )
+static inline IDirectPlayImpl *impl_from_IDirectPlay3( IDirectPlay3 *iface )
 {
-  IDirectPlay2AImpl *This = lpDP;
+    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay3_iface );
+}
 
-  This->unk->DP_lock.DebugInfo->Spare[0] = 0;
-  DeleteCriticalSection( &This->unk->DP_lock );
-  HeapFree( GetProcessHeap(), 0, This->unk );
+static inline IDirectPlayImpl *impl_from_IDirectPlay4A( IDirectPlay4A *iface )
+{
+    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4A_iface );
+}
 
-  return TRUE;
+static inline IDirectPlayImpl *impl_from_IDirectPlay4( IDirectPlay4 *iface )
+{
+    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4_iface );
 }
 
 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
 {
-  IDirectPlay2AImpl *This = lpDP;
+  IDirectPlayImpl *This = lpDP;
 
   This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
   if ( This->dp2 == NULL )
@@ -340,7 +207,7 @@ DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
 
 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
 {
-  IDirectPlay2AImpl *This = lpDP;
+  IDirectPlayImpl *This = lpDP;
 
   if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
   {
@@ -391,242 +258,12 @@ static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
   return TRUE;
 }
 
-static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
-{
-  IDirectPlay3AImpl *This = 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 = lpDP;
-
-  /* Delete the contents */
-  HeapFree( GetProcessHeap(), 0, This->dp3 );
-
-  return TRUE;
-}
-
-static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
-{
-  IDirectPlay4AImpl *This = 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 = lpDP;
-
-  /* Delete the contents */
-  HeapFree( GetProcessHeap(), 0, This->dp4 );
-
-  return TRUE;
-}
-
-
-/* Create a new interface */
-HRESULT DP_CreateInterface
-         ( REFIID riid, LPVOID* ppvObj )
+static void dplay_destroy(IDirectPlayImpl *obj)
 {
-  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 = *ppvObj;
-    This->lpVtbl = &directPlay2WVT;
-  }
-  else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
-  {
-    IDirectPlay2AImpl *This = *ppvObj;
-    This->lpVtbl = &directPlay2AVT;
-  }
-  else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
-  {
-    IDirectPlay3Impl *This = *ppvObj;
-    This->lpVtbl = &directPlay3WVT;
-  }
-  else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
-  {
-    IDirectPlay3AImpl *This = *ppvObj;
-    This->lpVtbl = &directPlay3AVT;
-  }
-  else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
-  {
-    IDirectPlay4Impl *This = *ppvObj;
-    This->lpVtbl = &directPlay4WVT;
-  }
-  else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
-  {
-    IDirectPlay4AImpl *This = *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 = *ppvObj;
-    This->lpVtbl = &directPlay2WVT;
-  }
-  else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
-  {
-    IDirectPlay2AImpl *This = *ppvObj;
-    This->lpVtbl = &directPlay2AVT;
-  }
-  else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
-  {
-    IDirectPlay3Impl *This = *ppvObj;
-    This->lpVtbl = &directPlay3WVT;
-  }
-  else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
-  {
-    IDirectPlay3AImpl *This = *ppvObj;
-    This->lpVtbl = &directPlay3AVT;
-  }
-  else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
-  {
-    IDirectPlay4Impl *This = *ppvObj;
-    This->lpVtbl = &directPlay4WVT;
-  }
-  else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
-  {
-    IDirectPlay4AImpl *This = *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 %u:%u 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 %u:%u 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;
+     DP_DestroyDirectPlay2( obj );
+     obj->lock.DebugInfo->Spare[0] = 0;
+     DeleteCriticalSection( &obj->lock );
+     HeapFree( GetProcessHeap(), 0, obj );
 }
 
 static inline DPID DP_NextObjectId(void)
@@ -635,10 +272,9 @@ static inline DPID DP_NextObjectId(void)
 }
 
 /* *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 )
+HRESULT DP_HandleMessage( IDirectPlayImpl *This, const void *lpcMessageBody,
+        DWORD dwMessageBodySize, const void *lpcMessageHeader, WORD wCommandId, WORD wVersion,
+        void **lplpReply, DWORD *lpdwMsgSize )
 {
   TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
          This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
@@ -731,150 +367,653 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
 }
 
 
-static HRESULT DP_IF_AddPlayerToGroup
-          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
-            DPID idPlayer, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlayImpl_QueryInterface( IDirectPlay *iface, REFIID riid, void **ppv )
 {
-  lpGroupData  lpGData;
-  lpPlayerList lpPList;
-  lpPlayerList lpNewPList;
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
+}
 
-  TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
-         This, lpMsgHdr, idGroup, idPlayer, bAnsi );
+static ULONG WINAPI IDirectPlayImpl_AddRef( IDirectPlay *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    ULONG ref = InterlockedIncrement( &This->ref );
 
-  if( This->dp2->connectionInitialized == NO_PROVIDER )
-  {
-    return DPERR_UNINITIALIZED;
-  }
+    TRACE( "(%p) ref=%d\n", This, ref );
 
-  /* Find the group */
-  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
-  {
-    return DPERR_INVALIDGROUP;
-  }
+    if ( ref == 1 )
+        InterlockedIncrement( &This->numIfaces );
 
-  /* Find the player */
-  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
-  {
-    return DPERR_INVALIDPLAYER;
-  }
+    return ref;
+}
 
-  /* Create a player list (ie "shortcut" ) */
-  lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
-  if( lpNewPList == NULL )
-  {
-    return DPERR_CANTADDPLAYER;
-  }
+static ULONG WINAPI IDirectPlayImpl_Release( IDirectPlay *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    ULONG ref = InterlockedDecrement( &This->ref );
 
-  /* Add the shortcut */
-  lpPList->lpPData->uRef++;
-  lpNewPList->lpPData = lpPList->lpPData;
+    TRACE( "(%p) ref=%d\n", This, ref );
 
-  /* Add the player to the list of players for this group */
-  DPQ_INSERT(lpGData->players,lpNewPList,players);
+    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
+        dplay_destroy( This );
 
-  /* Let the SP know that we've added a player to the group */
-  if( This->dp2->spData.lpCB->AddPlayerToGroup )
-  {
-    DPSP_ADDPLAYERTOGROUPDATA data;
+    return ref;
+}
 
-    TRACE( "Calling SP AddPlayerToGroup\n" );
+static HRESULT WINAPI IDirectPlayImpl_AddPlayerToGroup( IDirectPlay *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, player );
+    return E_NOTIMPL;
+}
 
-    data.idPlayer = idPlayer;
-    data.idGroup  = idGroup;
-    data.lpISP    = This->dp2->spData.lpISP;
+static HRESULT WINAPI IDirectPlayImpl_Close( IDirectPlay *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p): stub\n", This );
+    return E_NOTIMPL;
+}
 
-    (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
-  }
+static HRESULT WINAPI IDirectPlayImpl_CreatePlayer( IDirectPlay *iface, DPID *player,
+        LPSTR name, LPSTR fullname, HANDLE *event )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(%p,%s,%s,%p): stub\n", This, player, debugstr_a( name ), debugstr_a( fullname ),
+            event );
+    return E_NOTIMPL;
+}
 
-  /* 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;
+static HRESULT WINAPI IDirectPlayImpl_CreateGroup( IDirectPlay *iface, DPID *group, LPSTR name,
+        LPSTR fullname )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(%p,%s,%s): stub\n", This, group, debugstr_a( name ), debugstr_a( fullname ) );
+    return E_NOTIMPL;
+}
 
-    msg.dpIdGroup  = idGroup;
-    msg.dpIdPlayer = idPlayer;
+static HRESULT WINAPI IDirectPlayImpl_DeletePlayerFromGroup( IDirectPlay *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, player );
+    return E_NOTIMPL;
+}
 
-    /* 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 );
-  }
+static HRESULT WINAPI IDirectPlayImpl_DestroyPlayer( IDirectPlay *iface, DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x): stub\n", This, player );
+    return E_NOTIMPL;
+}
 
-  return DP_OK;
+static HRESULT WINAPI IDirectPlayImpl_DestroyGroup( IDirectPlay *iface, DPID group )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x): stub\n", This, group );
+    return E_NOTIMPL;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
-          ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
+static HRESULT WINAPI IDirectPlayImpl_EnableNewPlayers( IDirectPlay *iface, BOOL enable )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(%d): stub\n", This, enable );
+    return E_NOTIMPL;
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
-          ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
+static HRESULT WINAPI IDirectPlayImpl_EnumGroupPlayers( IDirectPlay *iface, DPID group,
+        LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, group, enumplayercb, context, flags );
+    return E_NOTIMPL;
 }
 
-static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlayImpl_EnumGroups( IDirectPlay *iface, DWORD session,
+        LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
 {
-  HRESULT hr = DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, session, enumplayercb, context, flags );
+    return E_NOTIMPL;
+}
 
-  TRACE("(%p)->(%u)\n", This, bAnsi );
+static HRESULT WINAPI IDirectPlayImpl_EnumPlayers( IDirectPlay *iface, DWORD session,
+        LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, session, enumplayercb, context, flags );
+    return E_NOTIMPL;
+}
 
-  /* 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 */
+static HRESULT WINAPI IDirectPlayImpl_EnumSessions( IDirectPlay *iface, DPSESSIONDESC *sdesc,
+        DWORD timeout, LPDPENUMSESSIONSCALLBACK enumsessioncb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(%p,%u,%p,%p,0x%08x): stub\n", This, sdesc, timeout, enumsessioncb, context,
+            flags );
+    return E_NOTIMPL;
+}
 
-  /* Invoke the SP callback to inform of session close */
-  if( This->dp2->spData.lpCB->CloseEx )
-  {
-    DPSP_CLOSEDATA data;
+static HRESULT WINAPI IDirectPlayImpl_GetCaps( IDirectPlay *iface, DPCAPS *caps )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(%p): stub\n", This, caps );
+    return E_NOTIMPL;
+}
 
-    TRACE( "Calling SP CloseEx\n" );
+static HRESULT WINAPI IDirectPlayImpl_GetMessageCount( IDirectPlay *iface, DPID player,
+        DWORD *count )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, count );
+    return E_NOTIMPL;
+}
 
-    data.lpISP = This->dp2->spData.lpISP;
+static HRESULT WINAPI IDirectPlayImpl_GetPlayerCaps( IDirectPlay *iface, DPID player, DPCAPS *caps )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, caps );
+    return E_NOTIMPL;
+}
 
-    hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
+static HRESULT WINAPI IDirectPlayImpl_GetPlayerName( IDirectPlay *iface, DPID player, LPSTR name,
+        DWORD *size_name, LPSTR fullname, DWORD *size_fullname )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x,%p,%p,%p,%p): stub\n", This, player, name, size_name, fullname,
+            size_fullname );
+    return E_NOTIMPL;
+}
 
-  }
-  else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
-  {
-    TRACE( "Calling SP Close (obsolete interface)\n" );
+static HRESULT WINAPI IDirectPlayImpl_Initialize( IDirectPlay *iface, GUID *guid )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(%p): stub\n", This, guid );
+    return E_NOTIMPL;
+}
 
-    hr = (*This->dp2->spData.lpCB->Close)();
-  }
+static HRESULT WINAPI IDirectPlayImpl_Open( IDirectPlay *iface, DPSESSIONDESC *sdesc )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(%p): stub\n", This, sdesc );
+    return E_NOTIMPL;
+}
 
-  return hr;
+static HRESULT WINAPI IDirectPlayImpl_Receive( IDirectPlay *iface, DPID *from, DPID *to,
+        DWORD flags, void *data, DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(%p,%p,0x%08x,%p,%p): stub\n", This, from, to, flags, data, size );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IDirectPlayImpl_SaveSession( IDirectPlay *iface, LPSTR reserved )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(%p): stub\n", This, reserved );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IDirectPlayImpl_Send( IDirectPlay *iface, DPID from, DPID to, DWORD flags,
+        void *data, DWORD size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%u): stub\n", This, from, to, flags, data, size );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IDirectPlayImpl_SetPlayerName( IDirectPlay *iface, DPID player, LPSTR name,
+        LPSTR fullname )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
+    FIXME( "(%p)->(0x%08x,%s,%s): stub\n", This, player, debugstr_a( name ),
+            debugstr_a ( fullname ) );
+    return E_NOTIMPL;
+}
+
+static const IDirectPlayVtbl dp_vt =
+{
+    IDirectPlayImpl_QueryInterface,
+    IDirectPlayImpl_AddRef,
+    IDirectPlayImpl_Release,
+    IDirectPlayImpl_AddPlayerToGroup,
+    IDirectPlayImpl_Close,
+    IDirectPlayImpl_CreatePlayer,
+    IDirectPlayImpl_CreateGroup,
+    IDirectPlayImpl_DeletePlayerFromGroup,
+    IDirectPlayImpl_DestroyPlayer,
+    IDirectPlayImpl_DestroyGroup,
+    IDirectPlayImpl_EnableNewPlayers,
+    IDirectPlayImpl_EnumGroupPlayers,
+    IDirectPlayImpl_EnumGroups,
+    IDirectPlayImpl_EnumPlayers,
+    IDirectPlayImpl_EnumSessions,
+    IDirectPlayImpl_GetCaps,
+    IDirectPlayImpl_GetMessageCount,
+    IDirectPlayImpl_GetPlayerCaps,
+    IDirectPlayImpl_GetPlayerName,
+    IDirectPlayImpl_Initialize,
+    IDirectPlayImpl_Open,
+    IDirectPlayImpl_Receive,
+    IDirectPlayImpl_SaveSession,
+    IDirectPlayImpl_Send,
+    IDirectPlayImpl_SetPlayerName,
+};
+
+
+static HRESULT WINAPI IDirectPlay2AImpl_QueryInterface( IDirectPlay2A *iface, REFIID riid,
+        void **ppv )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_QueryInterface( IDirectPlay2 *iface, REFIID riid,
+        void **ppv )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_QueryInterface( IDirectPlay3A *iface, REFIID riid,
+        void **ppv )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_QueryInterface( IDirectPlay3 *iface, REFIID riid,
+        void **ppv )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
+}
+
+static HRESULT WINAPI IDirectPlay4AImpl_QueryInterface( IDirectPlay4A *iface, REFIID riid,
+        void **ppv )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_QueryInterface( IDirectPlay4 *iface, REFIID riid,
+        void **ppv )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+
+    if ( IsEqualGUID( &IID_IUnknown, riid ) )
+    {
+        TRACE( "(%p)->(IID_IUnknown %p)\n", This, ppv );
+        *ppv = &This->IDirectPlay_iface;
+    }
+    else if ( IsEqualGUID( &IID_IDirectPlay, riid ) )
+    {
+        TRACE( "(%p)->(IID_IDirectPlay %p)\n", This, ppv );
+        *ppv = &This->IDirectPlay_iface;
+    }
+    else if ( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
+    {
+        TRACE( "(%p)->(IID_IDirectPlay2A %p)\n", This, ppv );
+        *ppv = &This->IDirectPlay2A_iface;
+    }
+    else if ( IsEqualGUID( &IID_IDirectPlay2, riid ) )
+    {
+        TRACE( "(%p)->(IID_IDirectPlay2 %p)\n", This, ppv );
+        *ppv = &This->IDirectPlay2_iface;
+    }
+    else if ( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
+    {
+        TRACE( "(%p)->(IID_IDirectPlay3A %p)\n", This, ppv );
+        *ppv = &This->IDirectPlay3A_iface;
+    }
+    else if ( IsEqualGUID( &IID_IDirectPlay3, riid ) )
+    {
+        TRACE( "(%p)->(IID_IDirectPlay3 %p)\n", This, ppv );
+        *ppv = &This->IDirectPlay3_iface;
+    }
+    else if ( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
+    {
+        TRACE( "(%p)->(IID_IDirectPlay4A %p)\n", This, ppv );
+        *ppv = &This->IDirectPlay4A_iface;
+    }
+    else if ( IsEqualGUID( &IID_IDirectPlay4, riid ) )
+    {
+        TRACE( "(%p)->(IID_IDirectPlay4 %p)\n", This, ppv );
+        *ppv = &This->IDirectPlay4_iface;
+    }
+    else
+    {
+        WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI IDirectPlay2AImpl_AddRef( IDirectPlay2A *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    ULONG ref = InterlockedIncrement( &This->ref2A );
+
+    TRACE( "(%p) ref2A=%d\n", This, ref );
+
+    if ( ref == 1 )
+        InterlockedIncrement( &This->numIfaces );
+
+    return ref;
+}
+
+static ULONG WINAPI IDirectPlay2Impl_AddRef( IDirectPlay2 *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    ULONG ref = InterlockedIncrement( &This->ref2 );
+
+    TRACE( "(%p) ref2=%d\n", This, ref );
+
+    if ( ref == 1 )
+        InterlockedIncrement( &This->numIfaces );
+
+    return ref;
+}
+
+static ULONG WINAPI IDirectPlay3AImpl_AddRef( IDirectPlay3A *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    ULONG ref = InterlockedIncrement( &This->ref3A );
+
+    TRACE( "(%p) ref3A=%d\n", This, ref );
+
+    if ( ref == 1 )
+        InterlockedIncrement( &This->numIfaces );
+
+    return ref;
+}
+
+static ULONG WINAPI IDirectPlay3Impl_AddRef( IDirectPlay3 *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    ULONG ref = InterlockedIncrement( &This->ref3 );
+
+    TRACE( "(%p) ref3=%d\n", This, ref );
+
+    if ( ref == 1 )
+        InterlockedIncrement( &This->numIfaces );
+
+    return ref;
+}
+
+static ULONG WINAPI IDirectPlay4AImpl_AddRef(IDirectPlay4A *iface)
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    ULONG ref = InterlockedIncrement( &This->ref4A );
+
+    TRACE( "(%p) ref4A=%d\n", This, ref );
+
+    if ( ref == 1 )
+        InterlockedIncrement( &This->numIfaces );
+
+    return ref;
+}
+
+static ULONG WINAPI IDirectPlay4Impl_AddRef(IDirectPlay4 *iface)
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    ULONG ref = InterlockedIncrement( &This->ref4 );
+
+    TRACE( "(%p) ref4=%d\n", This, ref );
+
+    if ( ref == 1 )
+        InterlockedIncrement( &This->numIfaces );
+
+    return ref;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_Close
-          ( LPDIRECTPLAY2A iface )
+static ULONG WINAPI IDirectPlay2AImpl_Release( IDirectPlay2A *iface )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_Close( This, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    ULONG ref = InterlockedDecrement( &This->ref2A );
+
+    TRACE( "(%p) ref2A=%d\n", This, ref );
+
+    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
+        dplay_destroy( This );
+
+    return ref;
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_Close
-          ( LPDIRECTPLAY2 iface )
+static ULONG WINAPI IDirectPlay2Impl_Release( IDirectPlay2 *iface )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_Close( This, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    ULONG ref = InterlockedDecrement( &This->ref2 );
+
+    TRACE( "(%p) ref2=%d\n", This, ref );
+
+    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
+        dplay_destroy( This );
+
+    return ref;
 }
 
-static
-lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
-                            const DPNAME *lpName, DWORD dwFlags,
-                            DPID idParent, BOOL bAnsi )
+static ULONG WINAPI IDirectPlay3AImpl_Release( IDirectPlay3A *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    ULONG ref = InterlockedDecrement( &This->ref3A );
+
+    TRACE( "(%p) ref3A=%d\n", This, ref );
+
+    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
+        dplay_destroy( This );
+
+    return ref;
+}
+
+static ULONG WINAPI IDirectPlay3Impl_Release( IDirectPlay3 *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    ULONG ref = InterlockedDecrement( &This->ref3 );
+
+    TRACE( "(%p) ref3=%d\n", This, ref );
+
+    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
+        dplay_destroy( This );
+
+    return ref;
+}
+
+static ULONG WINAPI IDirectPlay4AImpl_Release(IDirectPlay4A *iface)
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    ULONG ref = InterlockedDecrement( &This->ref4A );
+
+    TRACE( "(%p) ref4A=%d\n", This, ref );
+
+    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
+        dplay_destroy( This );
+
+    return ref;
+}
+
+static ULONG WINAPI IDirectPlay4Impl_Release(IDirectPlay4 *iface)
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    ULONG ref = InterlockedDecrement( &This->ref4 );
+
+    TRACE( "(%p) ref4=%d\n", This, ref );
+
+    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
+        dplay_destroy( This );
+
+    return ref;
+}
+
+static HRESULT WINAPI IDirectPlay2AImpl_AddPlayerToGroup( IDirectPlay2A *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4A_iface, group, player );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_AddPlayerToGroup( IDirectPlay2 *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_AddPlayerToGroup( IDirectPlay3A *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_AddPlayerToGroup( IDirectPlay3 *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
+}
+
+static HRESULT WINAPI IDirectPlay4AImpl_AddPlayerToGroup( IDirectPlay4A *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_AddPlayerToGroup( IDirectPlay4 *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    lpGroupData  gdata;
+    lpPlayerList plist;
+    lpPlayerList newplist;
+
+    TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );
+
+    if ( This->dp2->connectionInitialized == NO_PROVIDER )
+        return DPERR_UNINITIALIZED;
+
+    /* Find the group */
+    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
+        return DPERR_INVALIDGROUP;
+
+    /* Find the player */
+    if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
+        return DPERR_INVALIDPLAYER;
+
+    /* Create a player list (ie "shortcut" ) */
+    newplist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *newplist ) );
+    if ( !newplist )
+        return DPERR_CANTADDPLAYER;
+
+    /* Add the shortcut */
+    plist->lpPData->uRef++;
+    newplist->lpPData = plist->lpPData;
+
+    /* Add the player to the list of players for this group */
+    DPQ_INSERT(gdata->players, newplist, 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 = player;
+        data.idGroup  = group;
+        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 ( This->dp2->lpSessionDesc &&
+            ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
+    {
+        DPMSG_ADDPLAYERTOGROUP msg;
+        msg.dwType = DPSYS_ADDPLAYERTOGROUP;
+
+        msg.dpIdGroup  = group;
+        msg.dpIdPlayer = player;
+
+        /* FIXME: Correct to just use send effectively? */
+        /* FIXME: Should size include data w/ message or just message "header" */
+        /* FIXME: Check return code */
+        IDirectPlayX_SendEx( iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
+                0, 0, NULL, NULL );
+    }
+
+    return DP_OK;
+}
+
+static HRESULT WINAPI IDirectPlay2AImpl_Close( IDirectPlay2A *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_Close( &This->IDirectPlay4A_iface );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_Close( IDirectPlay2 *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_Close( &This->IDirectPlay4_iface );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_Close( IDirectPlay3A *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_Close( &This->IDirectPlay4_iface );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_Close( IDirectPlay3 *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_Close( &This->IDirectPlay4_iface );
+}
+
+static HRESULT WINAPI IDirectPlay4AImpl_Close( IDirectPlay4A *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_Close( &This->IDirectPlay4_iface);
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_Close( IDirectPlay4 *iface )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    HRESULT hr = DP_OK;
+
+    TRACE( "(%p)\n", This );
+
+    /* 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 lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, const DPNAME *lpName,
+        DWORD dwFlags, DPID idParent, BOOL bAnsi )
 {
   lpGroupData lpGData;
 
@@ -906,8 +1045,7 @@ lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
 }
 
 /* This method assumes that all links to it are already deleted */
-static void
-DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
+static void DP_DeleteGroup( IDirectPlayImpl *This, DPID dpid )
 {
   lpGroupList lpGList;
 
@@ -936,7 +1074,7 @@ DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
 
 }
 
-static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
+static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid )
 {
   lpGroupList lpGroups;
 
@@ -959,10 +1097,8 @@ static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
   return lpGroups->lpGData;
 }
 
-static HRESULT DP_IF_CreateGroup
-          ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
-            LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
-            DWORD dwFlags, BOOL bAnsi )
+static HRESULT DP_IF_CreateGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidGroup,
+        DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
 {
   lpGroupData lpGData;
 
@@ -1071,31 +1207,65 @@ static HRESULT DP_IF_CreateGroup
     /* 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 );
+    IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
+            sizeof( msg ), 0, 0, NULL, NULL );
   }
 
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
-          ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
-            LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2AImpl_CreateGroup( IDirectPlay2A *iface, DPID *lpidGroup,
+        DPNAME *name, void *data, DWORD size, DWORD flags )
 {
-  *lpidGroup = DPID_UNKNOWN;
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_CreateGroup( &This->IDirectPlay4A_iface, lpidGroup, name, data, size,
+            flags );
+}
 
-  return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
-                            lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
+static HRESULT WINAPI IDirectPlay2Impl_CreateGroup( IDirectPlay2 *iface, DPID *lpidGroup,
+        DPNAME *name, void *data, DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, lpidGroup, name, data, size,
+            flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
-          ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
-            LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3AImpl_CreateGroup( IDirectPlay3A *iface, DPID *group,
+        DPNAME *name, void *data, DWORD size, DWORD flags )
 {
-  *lpidGroup = DPID_UNKNOWN;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, group, name, data, size,
+            flags );
+}
 
-  return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
-                            lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
+static HRESULT WINAPI IDirectPlay3Impl_CreateGroup( IDirectPlay3 *iface, DPID *lpidGroup,
+        DPNAME *name, void *data, DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, lpidGroup, name, data, size,
+            flags );
+}
+
+static HRESULT WINAPI IDirectPlay4AImpl_CreateGroup( IDirectPlay4A *iface, DPID *lpidGroup,
+        DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+
+    *lpidGroup = DPID_UNKNOWN;
+
+    return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
+            TRUE );
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_CreateGroup( IDirectPlay4 *iface, DPID *lpidGroup,
+        DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+
+    *lpidGroup = DPID_UNKNOWN;
+
+    return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
+            FALSE );
 }
 
 
@@ -1142,10 +1312,8 @@ DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
 }
 
 /* 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 )
+static lpPlayerData DP_CreatePlayer( IDirectPlayImpl *This, DPID *lpid, DPNAME *lpName,
+        DWORD dwFlags, HANDLE hEvent, BOOL bAnsi )
 {
   lpPlayerData lpPData;
 
@@ -1198,8 +1366,7 @@ DP_DeleteDPNameStruct( LPDPNAME lpDPName )
 }
 
 /* This method assumes that all links to it are already deleted */
-static void
-DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
+static void DP_DeletePlayer( IDirectPlayImpl *This, DPID dpid )
 {
   lpPlayerList lpPList;
 
@@ -1230,7 +1397,7 @@ DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
   HeapFree( GetProcessHeap(), 0, lpPList );
 }
 
-static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
+static lpPlayerList DP_FindPlayer( IDirectPlayImpl *This, DPID dpid )
 {
   lpPlayerList lpPlayers;
 
@@ -1343,16 +1510,10 @@ DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
 
 }
 
-static HRESULT 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 )
+/* Note: lpMsgHdr is NULL for local creation, non NULL for remote creation */
+static HRESULT DP_IF_CreatePlayer( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidPlayer,
+        DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags,
+        BOOL bAnsi )
 {
   HRESULT hr = DP_OK;
   lpPlayerData lpPData;
@@ -1551,19 +1712,50 @@ static HRESULT DP_IF_CreatePlayer
     /* FIXME: Correct to just use send effectively? */
     /* FIXME: Should size include data w/ message or just message "header" */
     /* FIXME: Check return code */
-    hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
-                    sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
+    hr = IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0,
+            &msg, sizeof( msg ), 0, 0, NULL, NULL );
   }
 #endif
 
   return hr;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
-          ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
-            HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2AImpl_CreatePlayer( IDirectPlay2A *iface, DPID *lpidPlayer,
+        DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_CreatePlayer( &This->IDirectPlay4A_iface, lpidPlayer, name, event, data,
+            size, flags );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_CreatePlayer( IDirectPlay2 *iface, DPID *lpidPlayer,
+        DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
+            size, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_CreatePlayer( IDirectPlay3A *iface, DPID *lpidPlayer,
+        DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
+            size, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_CreatePlayer( IDirectPlay3 *iface, DPID *lpidPlayer,
+        DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
+            size, flags );
+}
+
+static HRESULT WINAPI IDirectPlay4AImpl_CreatePlayer( IDirectPlay4A *iface, DPID *lpidPlayer,
+        DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
+{
+  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
 
   if( lpidPlayer == NULL )
   {
@@ -1583,11 +1775,10 @@ static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
                            lpData, dwDataSize, dwFlags, TRUE );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
-          ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
-            HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4Impl_CreatePlayer( IDirectPlay4 *iface, DPID *lpidPlayer,
+        DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
+  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
 
   if( lpidPlayer == NULL )
   {
@@ -1615,81 +1806,93 @@ static DPID DP_GetRemoteNextObjectId(void)
   return DP_NextObjectId();
 }
 
-static HRESULT DP_IF_DeletePlayerFromGroup
-          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
-            DPID idPlayer, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay2AImpl_DeletePlayerFromGroup( IDirectPlay2A *iface, DPID group,
+        DPID player )
 {
-  HRESULT hr = DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4A_iface, group, player );
+}
 
-  lpGroupData  lpGData;
-  lpPlayerList lpPList;
+static HRESULT WINAPI IDirectPlay2Impl_DeletePlayerFromGroup( IDirectPlay2 *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
+}
 
-  TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
-         This, lpMsgHdr, idGroup, idPlayer, bAnsi );
+static HRESULT WINAPI IDirectPlay3AImpl_DeletePlayerFromGroup( IDirectPlay3A *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
+}
 
-  /* Find the group */
-  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
-  {
-    return DPERR_INVALIDGROUP;
-  }
+static HRESULT WINAPI IDirectPlay3Impl_DeletePlayerFromGroup( IDirectPlay3 *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
+}
 
-  /* Find the player */
-  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
-  {
-    return DPERR_INVALIDPLAYER;
-  }
+static HRESULT WINAPI IDirectPlay4AImpl_DeletePlayerFromGroup( IDirectPlay4A *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
+}
 
-  /* Remove the player shortcut from the group */
-  DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
+static HRESULT WINAPI IDirectPlay4Impl_DeletePlayerFromGroup( IDirectPlay4 *iface, DPID group,
+        DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    HRESULT hr = DP_OK;
 
-  if( lpPList == NULL )
-  {
-    return DPERR_INVALIDPLAYER;
-  }
+    lpGroupData  gdata;
+    lpPlayerList plist;
 
-  /* One less reference */
-  lpPList->lpPData->uRef--;
+    TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );
 
-  /* Delete the Player List element */
-  HeapFree( GetProcessHeap(), 0, lpPList );
+    /* Find the group */
+    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
+        return DPERR_INVALIDGROUP;
 
-  /* Inform the SP if they care */
-  if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
-  {
-    DPSP_REMOVEPLAYERFROMGROUPDATA data;
+    /* Find the player */
+    if ( DP_FindPlayer( This, player ) == NULL )
+        return DPERR_INVALIDPLAYER;
 
-    TRACE( "Calling SP RemovePlayerFromGroup\n" );
+    /* Remove the player shortcut from the group */
+    DPQ_REMOVE_ENTRY( gdata->players, players, lpPData->dpid, ==, player, plist );
 
-    data.idPlayer = idPlayer;
-    data.idGroup  = idGroup;
-    data.lpISP    = This->dp2->spData.lpISP;
+    if ( !plist )
+        return DPERR_INVALIDPLAYER;
 
-    hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
-  }
+    /* One less reference */
+    plist->lpPData->uRef--;
 
-  /* Need to send a DELETEPLAYERFROMGROUP message */
-  FIXME( "Need to send a message\n" );
+    /* Delete the Player List element */
+    HeapFree( GetProcessHeap(), 0, plist );
 
-  return hr;
-}
+    /* Inform the SP if they care */
+    if ( This->dp2->spData.lpCB->RemovePlayerFromGroup )
+    {
+        DPSP_REMOVEPLAYERFROMGROUPDATA data;
 
-static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
-          ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
-{
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
-}
+        TRACE( "Calling SP RemovePlayerFromGroup\n" );
+        data.idPlayer = player;
+        data.idGroup = group;
+        data.lpISP = This->dp2->spData.lpISP;
+        hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
+    }
 
-static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
-          ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
-{
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
+    /* Need to send a DELETEPLAYERFROMGROUP message */
+    FIXME( "Need to send a message\n" );
+
+    return hr;
 }
 
 typedef struct _DPRGOPContext
 {
-  IDirectPlay3Impl* This;
+  IDirectPlayImpl   *This;
   BOOL              bAnsi;
   DPID              idGroup;
 } DPRGOPContext, *lpDPRGOPContext;
@@ -1709,33 +1912,18 @@ cbRemoveGroupOrPlayer(
 
   if( dwPlayerType == DPPLAYERTYPE_GROUP )
   {
-    if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
-                                            dpId )
-              )
-      )
-    {
-      ERR( "Unable to delete group 0x%08x from group 0x%08x\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%08x from grp 0x%08x\n",
-             dpId, lpCtxt->idGroup );
-    }
+    if ( FAILED( IDirectPlayX_DeleteGroupFromGroup( &lpCtxt->This->IDirectPlay4_iface,
+                    lpCtxt->idGroup, dpId ) ) )
+      ERR( "Unable to delete group 0x%08x from group 0x%08x\n", dpId, lpCtxt->idGroup );
   }
+  else if ( FAILED( IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface,
+                                                        lpCtxt->idGroup, dpId ) ) )
+      ERR( "Unable to delete player 0x%08x from grp 0x%08x\n", dpId, lpCtxt->idGroup );
 
   return TRUE; /* Continue enumeration */
 }
 
-static HRESULT DP_IF_DestroyGroup
-          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
+static HRESULT DP_IF_DestroyGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID idGroup, BOOL bAnsi )
 {
   lpGroupData lpGData;
   DPRGOPContext context;
@@ -1749,26 +1937,21 @@ static HRESULT DP_IF_DestroyGroup
     return DPERR_INVALIDPLAYER; /* yes player */
   }
 
-  context.This    = (IDirectPlay3Impl*)This;
+  context.This    = This;
   context.bAnsi   = bAnsi;
   context.idGroup = idGroup;
 
   /* Remove all players that this group has */
-  DP_IF_EnumGroupPlayers( This, idGroup, NULL,
-                          cbRemoveGroupOrPlayer, &context, 0, bAnsi );
+  IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, idGroup, NULL, cbRemoveGroupOrPlayer,
+          &context, 0 );
 
   /* 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 );
+  IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, idGroup, NULL, cbRemoveGroupOrPlayer,
+          (void*)&context, 0 );
 
   /* 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 );
-  }
+  if( ( idGroup != DPID_SYSTEM_GROUP ) && ( lpGData->parent != DPID_SYSTEM_GROUP ) )
+    IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, lpGData->parent, idGroup );
 
   /* Now delete this group data and list from the system group */
   DP_DeleteGroup( This, idGroup );
@@ -1792,29 +1975,51 @@ static HRESULT DP_IF_DestroyGroup
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
-          ( LPDIRECTPLAY2A iface, DPID idGroup )
+static HRESULT WINAPI IDirectPlay2AImpl_DestroyGroup( IDirectPlay2A *iface, DPID group )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_DestroyGroup( &This->IDirectPlay4A_iface, group );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_DestroyGroup( IDirectPlay2 *iface, DPID group )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_DestroyGroup( IDirectPlay3A *iface, DPID group )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_DestroyGroup( IDirectPlay3 *iface, DPID group )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
-          ( LPDIRECTPLAY2 iface, DPID idGroup )
+static HRESULT WINAPI IDirectPlay4AImpl_DestroyGroup( IDirectPlay4A *iface, DPID idGroup )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_DestroyGroup( IDirectPlay4 *iface, DPID idGroup )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
 }
 
 typedef struct _DPFAGContext
 {
-  IDirectPlay2Impl* This;
+  IDirectPlayImpl   *This;
   DPID              idPlayer;
   BOOL              bAnsi;
 } DPFAGContext, *lpDPFAGContext;
 
-static HRESULT DP_IF_DestroyPlayer
-          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
+static HRESULT DP_IF_DestroyPlayer( IDirectPlayImpl *This, void *lpMsgHdr, DPID idPlayer,
+        BOOL bAnsi )
 {
   DPFAGContext cbContext;
 
@@ -1839,8 +2044,8 @@ static HRESULT DP_IF_DestroyPlayer
 
   /* Find each group and call DeletePlayerFromGroup if the player is a
      member of the group */
-  DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
-                    &cbContext, DPENUMGROUPS_ALL, bAnsi );
+  IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, NULL, cbDeletePlayerFromAllGroups, &cbContext,
+          DPENUMGROUPS_ALL );
 
   /* Now delete player and player list from the sys group */
   DP_DeletePlayer( This, idPlayer );
@@ -1876,17 +2081,13 @@ cbDeletePlayerFromAllGroups(
 
   if( dwPlayerType == DPPLAYERTYPE_GROUP )
   {
-    DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
-                                 lpCtxt->bAnsi );
+    IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, lpCtxt->idPlayer );
 
     /* 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,
-                             lpContext, DPENUMGROUPS_ALL,
-                             lpCtxt->bAnsi );
+    IDirectPlayX_EnumGroupsInGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, NULL,
+            cbDeletePlayerFromAllGroups, lpContext, DPENUMGROUPS_ALL);
 
   }
   else
@@ -1894,170 +2095,218 @@ cbDeletePlayerFromAllGroups(
     ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
   }
 
-  return TRUE;
+  return TRUE;
+}
+
+static HRESULT WINAPI IDirectPlay2AImpl_DestroyPlayer( IDirectPlay2A *iface, DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4A_iface, player );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_DestroyPlayer( IDirectPlay2 *iface, DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_DestroyPlayer( IDirectPlay3A *iface, DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_DestroyPlayer( IDirectPlay3 *iface, DPID player )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
-          ( LPDIRECTPLAY2A iface, DPID idPlayer )
+static HRESULT WINAPI IDirectPlay4AImpl_DestroyPlayer( IDirectPlay4A *iface, DPID idPlayer )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
-          ( LPDIRECTPLAY2 iface, DPID idPlayer )
+static HRESULT WINAPI IDirectPlay4Impl_DestroyPlayer( IDirectPlay4 *iface, DPID idPlayer )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
 }
 
-static HRESULT DP_IF_EnumGroupPlayers
-          ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay2AImpl_EnumGroupPlayers( IDirectPlay2A *iface, DPID group,
+        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
 {
-  lpGroupData  lpGData;
-  lpPlayerList lpPList;
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4A_iface, group, instance,
+            enumplayercb, context, flags );
+}
 
-  FIXME("(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
-          This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
-          lpContext, dwFlags, bAnsi );
+static HRESULT WINAPI IDirectPlay2Impl_EnumGroupPlayers( IDirectPlay2 *iface, DPID group,
+        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
+            enumplayercb, context, flags );
+}
 
-  if( This->dp2->connectionInitialized == NO_PROVIDER )
-  {
-    return DPERR_UNINITIALIZED;
-  }
+static HRESULT WINAPI IDirectPlay3AImpl_EnumGroupPlayers( IDirectPlay3A *iface, DPID group,
+        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
+            enumplayercb, context, flags );
+}
 
-  /* Find the group */
-  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
-  {
-    return DPERR_INVALIDGROUP;
-  }
+static HRESULT WINAPI IDirectPlay3Impl_EnumGroupPlayers( IDirectPlay3 *iface, DPID group,
+        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
+            enumplayercb, context, flags );
+}
 
-  if( DPQ_IS_EMPTY( lpGData->players ) )
-  {
-    return DP_OK;
-  }
+static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupPlayers( IDirectPlay4A *iface, DPID group,
+        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance, enumplayercb,
+            context, flags );
+}
 
-  lpPList = DPQ_FIRST( lpGData->players );
+static HRESULT WINAPI IDirectPlay4Impl_EnumGroupPlayers( IDirectPlay4 *iface, DPID group,
+        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    lpGroupData  gdata;
+    lpPlayerList plist;
 
-  /* Walk the players in this group */
-  for( ;; )
-  {
-    /* We do not enum the name server or app server as they are of no
-     * consequence to the end user.
-     */
-    if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
-        ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
-      )
-    {
+    FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
+           context, flags );
 
-      /* FIXME: Need to add stuff for dwFlags checking */
+    if ( This->dp2->connectionInitialized == NO_PROVIDER )
+        return DPERR_UNINITIALIZED;
 
-      if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
-                                   &lpPList->lpPData->name,
-                                   lpPList->lpPData->dwFlags,
-                                   lpContext )
-        )
-      {
-        /* User requested break */
+    /* Find the group */
+    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
+        return DPERR_INVALIDGROUP;
+
+    if ( DPQ_IS_EMPTY( gdata->players ) )
         return DP_OK;
-      }
-    }
 
-    if( DPQ_IS_ENDOFLIST( lpPList->players ) )
+    /* Walk the players in this group */
+    for( plist = DPQ_FIRST( gdata->players ); ; plist = DPQ_NEXT( plist->players ) )
     {
-      break;
+        /* We do not enum the name server or app server as they are of no
+         * consequence to the end user.
+         */
+        if ( ( plist->lpPData->dpid != DPID_NAME_SERVER ) &&
+                ( plist->lpPData->dpid != DPID_SERVERPLAYER ) )
+        {
+            /* FIXME: Need to add stuff for flags checking */
+            if ( !enumplayercb( plist->lpPData->dpid, DPPLAYERTYPE_PLAYER,
+                        &plist->lpPData->name, plist->lpPData->dwFlags, context ) )
+              /* User requested break */
+              return DP_OK;
+        }
+
+        if ( DPQ_IS_ENDOFLIST( plist->players ) )
+            break;
     }
+    return DP_OK;
+}
 
-    lpPList = DPQ_NEXT( lpPList->players );
-  }
+/* NOTE: This only enumerates top level groups (created with CreateGroup) */
+static HRESULT WINAPI IDirectPlay2AImpl_EnumGroups( IDirectPlay2A *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_EnumGroups( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
+            flags );
+}
 
-  return DP_OK;
+static HRESULT WINAPI IDirectPlay2Impl_EnumGroups( IDirectPlay2 *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
+            flags );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
-          ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3AImpl_EnumGroups( IDirectPlay3A *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
-                               lpEnumPlayersCallback2, lpContext,
-                               dwFlags, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
+            flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
-          ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3Impl_EnumGroups( IDirectPlay3 *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
-                               lpEnumPlayersCallback2, lpContext,
-                               dwFlags, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
+            flags );
 }
 
-/* NOTE: This only enumerates top level groups (created with CreateGroup) */
-static HRESULT DP_IF_EnumGroups
-          ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay4AImpl_EnumGroups( IDirectPlay4A *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
+            context, flags );
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_EnumGroups ( IDirectPlay4 *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
+            context, flags );
+}
+
+static HRESULT WINAPI IDirectPlay2AImpl_EnumPlayers( IDirectPlay2A *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
 {
-  return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
-                                  DPID_SYSTEM_GROUP, lpguidInstance,
-                                  lpEnumPlayersCallback2, lpContext,
-                                  dwFlags, bAnsi );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_EnumPlayers( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
+            flags );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
-          ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2Impl_EnumPlayers( IDirectPlay2 *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
-                         lpContext, dwFlags, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
+            flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
-          ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3AImpl_EnumPlayers( IDirectPlay3A *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
-                         lpContext, dwFlags, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
+            flags );
 }
 
-static HRESULT DP_IF_EnumPlayers
-          ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay3Impl_EnumPlayers( IDirectPlay3 *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
 {
-  return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
-                                 lpEnumPlayersCallback2, lpContext,
-                                 dwFlags, bAnsi );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
+            flags );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
-          ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4AImpl_EnumPlayers( IDirectPlay4A *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
-                          lpContext, dwFlags, TRUE );
+    return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
+            context, flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
-          ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4Impl_EnumPlayers( IDirectPlay4 *iface, GUID *instance,
+        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
-                          lpContext, dwFlags, FALSE );
+    return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
+            context, flags );
 }
 
 /* This function should call the registered callback function that the user
@@ -2141,7 +2390,7 @@ static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
   return 1;
 }
 
-static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
+static void DP_KillEnumSessionThread( IDirectPlayImpl *This )
 {
   /* Does a thread exist? If so we were doing an async enum session */
   if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
@@ -2160,295 +2409,278 @@ static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
   }
 }
 
-static HRESULT DP_IF_EnumSessions
-          ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
-            LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
-            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay2AImpl_EnumSessions( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
+        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
 {
-  HRESULT hr = DP_OK;
-
-  TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x,%u)\n",
-         This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
-         bAnsi );
-  if( This->dp2->connectionInitialized == NO_PROVIDER )
-  {
-    return DPERR_UNINITIALIZED;
-  }
-
-  /* Can't enumerate if the interface is already open */
-  if( This->dp2->bConnectionOpen )
-  {
-    return DPERR_GENERIC;
-  }
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_EnumSessions( &This->IDirectPlay4A_iface, sdesc, timeout, enumsessioncb,
+            context, flags );
+}
 
-#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
+static HRESULT WINAPI IDirectPlay2Impl_EnumSessions( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
+        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
+            context, flags );
+}
 
+static HRESULT WINAPI IDirectPlay3AImpl_EnumSessions( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
+        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
+            context, flags );
+}
 
-  /* Use the service provider default? */
-  if( dwTimeout == 0 )
-  {
-    DPCAPS spCaps;
-    spCaps.dwSize = sizeof( spCaps );
+static HRESULT WINAPI IDirectPlay3Impl_EnumSessions( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
+        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
+            context, flags );
+}
 
-    DP_IF_GetCaps( This, &spCaps, 0 );
-    dwTimeout = spCaps.dwTimeout;
+static HRESULT WINAPI IDirectPlay4AImpl_EnumSessions( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
+        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
+            context, flags );
+}
 
-    /* The service provider doesn't provide one either! */
-    if( dwTimeout == 0 )
-    {
-      /* Provide the TCP/IP default */
-      dwTimeout = DPMSG_WAIT_5_SECS;
-    }
-  }
+static HRESULT WINAPI IDirectPlay4Impl_EnumSessions( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
+        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    void *connection;
+    DWORD  size;
+    HRESULT hr = DP_OK;
 
-  if( dwFlags & DPENUMSESSIONS_STOPASYNC )
-  {
-    DP_KillEnumSessionThread( This );
-    return hr;
-  }
+    TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x)\n", This, sdesc, timeout, enumsessioncb,
+            context, flags );
 
-  if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
-  {
-    /* Enumerate everything presently in the local session cache */
-    DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
-                                   This->dp2->lpNameServerData, dwTimeout,
-                                   lpContext );
+    if ( This->dp2->connectionInitialized == NO_PROVIDER )
+        return DPERR_UNINITIALIZED;
 
-    if( This->dp2->dwEnumSessionLock != 0 )
-      return DPERR_CONNECTING;
+    /* Can't enumerate if the interface is already open */
+    if ( This->dp2->bConnectionOpen )
+        return DPERR_GENERIC;
 
-    /* See if we've already created a thread to service this interface */
-    if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
+    /* 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 )
     {
-      DWORD dwThreadId;
-      This->dp2->dwEnumSessionLock++;
+        WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
 
-      /* 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( SUCCEEDED(hr) )
-      {
-        EnumSessionAsyncCallbackData* lpData
-          = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
-        /* FIXME: need to kill the thread on object deletion */
-        lpData->lpSpData  = &This->dp2->spData;
-
-        lpData->requestGuid = lpsd->guidApplication;
-        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 )
-          )
+        if ( !DP_BuildSPCompoundAddr( (GUID*)&DPSPGUID_TCPIP, &connection, &size ) )
         {
-          ERR( "Can't duplicate thread killing handle\n" );
+            ERR( "Can't build compound addr\n" );
+            return DPERR_GENERIC;
         }
 
-        TRACE( ": creating EnumSessionsRequest thread\n" );
+        hr = IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, 0 );
+        if ( FAILED(hr) )
+            return hr;
 
-        This->dp2->hEnumSessionThread = CreateThread( NULL,
-                                                      0,
-                                                      DP_EnumSessionsSendAsyncRequestThread,
-                                                      lpData,
-                                                      0,
-                                                      &dwThreadId );
-      }
-      This->dp2->dwEnumSessionLock--;
+        HeapFree( GetProcessHeap(), 0, connection );
+        This->dp2->bSPInitialized = TRUE;
     }
-  }
-  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 );
 
+    /* Use the service provider default? */
+    if ( !timeout )
+    {
+        DPCAPS caps;
+        caps.dwSize = sizeof( caps );
 
-    SleepEx( dwTimeout, FALSE );
+        IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, &caps, 0 );
+        timeout = caps.dwTimeout;
+        if ( !timeout )
+            timeout = DPMSG_WAIT_5_SECS; /* Provide the TCP/IP default */
+    }
 
-    DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
-                                   This->dp2->lpNameServerData, dwTimeout,
-                                   lpContext );
-  }
+    if ( flags & DPENUMSESSIONS_STOPASYNC )
+    {
+        DP_KillEnumSessionThread( This );
+        return hr;
+    }
 
-  return hr;
+    if ( flags & DPENUMSESSIONS_ASYNC )
+    {
+        /* Enumerate everything presently in the local session cache */
+        DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
+                context );
+
+        if ( This->dp2->dwEnumSessionLock )
+            return DPERR_CONNECTING;
+
+        /* See if we've already created a thread to service this interface */
+        if ( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
+        {
+            DWORD tid;
+            This->dp2->dwEnumSessionLock++;
+
+            /* 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( &sdesc->guidApplication, flags,
+                    &This->dp2->spData );
+
+            if ( SUCCEEDED(hr) )
+            {
+                EnumSessionAsyncCallbackData* data = HeapAlloc( GetProcessHeap(),
+                        HEAP_ZERO_MEMORY, sizeof( *data ) );
+                /* FIXME: need to kill the thread on object deletion */
+                data->lpSpData  = &This->dp2->spData;
+                data->requestGuid = sdesc->guidApplication;
+                data->dwEnumSessionFlags = flags;
+                data->dwTimeout = timeout;
+
+                This->dp2->hKillEnumSessionThreadEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
+                if ( !DuplicateHandle( GetCurrentProcess(), This->dp2->hKillEnumSessionThreadEvent,
+                            GetCurrentProcess(), &data->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, data, 0, &tid );
+            }
+            This->dp2->dwEnumSessionLock--;
+        }
+    }
+    else
+    {
+        /* Invalidate the session cache for the interface */
+        NS_InvalidateSessionCache( This->dp2->lpNameServerData );
+        /* Send the broadcast for session enumeration */
+        hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags, &This->dp2->spData );
+        SleepEx( timeout, FALSE );
+        DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
+                context );
+    }
+
+    return hr;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
-          ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
-            LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
-            LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2AImpl_GetCaps( IDirectPlay2A *iface, DPCAPS *caps, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
-                             lpContext, dwFlags, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_GetCaps( &This->IDirectPlay4A_iface, caps, flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
-          ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
-            LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
-            LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2Impl_GetCaps( IDirectPlay2 *iface, DPCAPS *caps, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
-                             lpContext, dwFlags, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
 }
 
-static HRESULT DP_IF_GetPlayerCaps
-          ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3AImpl_GetCaps( IDirectPlay3A *iface, DPCAPS *caps, DWORD flags )
 {
-  DPSP_GETCAPSDATA data;
-
-  TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
+}
 
-  if ( This->dp2->connectionInitialized == NO_PROVIDER )
-  {
-    return DPERR_UNINITIALIZED;
-  }
+static HRESULT WINAPI IDirectPlay3Impl_GetCaps( IDirectPlay3 *iface, DPCAPS *caps, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
+}
 
-  /* Query the service provider */
-  data.idPlayer = idPlayer;
-  data.dwFlags  = dwFlags;
-  data.lpCaps   = lpDPCaps;
-  data.lpISP    = This->dp2->spData.lpISP;
+static HRESULT WINAPI IDirectPlay4AImpl_GetCaps( IDirectPlay4A *iface, DPCAPS *caps, DWORD flags )
+{
+    return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
+}
 
-  return (*This->dp2->spData.lpCB->GetCaps)( &data );
+static HRESULT WINAPI IDirectPlay4Impl_GetCaps( IDirectPlay4 *iface, DPCAPS *caps, DWORD flags )
+{
+    return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
 }
 
-static HRESULT DP_IF_GetCaps
-          ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2AImpl_GetGroupData( IDirectPlay2A *iface, DPID group, void *data,
+        DWORD *size, DWORD flags )
 {
-  return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_GetGroupData( &This->IDirectPlay4A_iface, group, data, size, flags );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetCaps
-          ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2Impl_GetGroupData( IDirectPlay2 *iface, DPID group, void *data,
+        DWORD *size, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetCaps
-          ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3AImpl_GetGroupData( IDirectPlay3A *iface, DPID group, void *data,
+        DWORD *size, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
 }
 
-static HRESULT DP_IF_GetGroupData
-          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
-            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay3Impl_GetGroupData( IDirectPlay3 *iface, DPID group, void *data,
+        DWORD *size, DWORD flags )
 {
-  lpGroupData lpGData;
-  DWORD dwRequiredBufferSize;
-  LPVOID lpCopyDataFrom;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
+}
 
-  TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
-         This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
+static HRESULT WINAPI IDirectPlay4AImpl_GetGroupData( IDirectPlay4A *iface, DPID group,
+        void *data, DWORD *size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
+}
 
-  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
-  {
-    return DPERR_INVALIDGROUP;
-  }
+static HRESULT WINAPI IDirectPlay4Impl_GetGroupData( IDirectPlay4 *iface, DPID group,
+        void *data, DWORD *size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    lpGroupData gdata;
+    DWORD bufsize;
+    void *src;
 
-  /* How much buffer is required? */
-  if( dwFlags & DPSET_LOCAL )
-  {
-    dwRequiredBufferSize = lpGData->dwLocalDataSize;
-    lpCopyDataFrom       = lpGData->lpLocalData;
-  }
-  else
-  {
-    dwRequiredBufferSize = lpGData->dwRemoteDataSize;
-    lpCopyDataFrom       = lpGData->lpRemoteData;
-  }
+    TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, group, data, size, flags );
 
-  /* Is the user requesting to know how big a buffer is required? */
-  if( ( lpData == NULL ) ||
-      ( *lpdwDataSize < dwRequiredBufferSize )
-    )
-  {
-    *lpdwDataSize = dwRequiredBufferSize;
-    return DPERR_BUFFERTOOSMALL;
-  }
+    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
+        return DPERR_INVALIDGROUP;
 
-  CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
+    /* How much buffer is required? */
+    if ( flags & DPSET_LOCAL )
+    {
+        bufsize = gdata->dwLocalDataSize;
+        src = gdata->lpLocalData;
+    }
+    else
+    {
+        bufsize = gdata->dwRemoteDataSize;
+        src = gdata->lpRemoteData;
+    }
 
-  return DP_OK;
-}
+    /* Is the user requesting to know how big a buffer is required? */
+    if ( !data || *size < bufsize )
+    {
+        *size = bufsize;
+        return DPERR_BUFFERTOOSMALL;
+    }
 
-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 );
-}
+    CopyMemory( data, src, bufsize );
 
-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 );
+    return DP_OK;
 }
 
-static HRESULT DP_IF_GetGroupName
-          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
-            LPDWORD lpdwDataSize, BOOL bAnsi )
+static HRESULT DP_IF_GetGroupName( IDirectPlayImpl *This, DPID idGroup, void *lpData,
+        DWORD *lpdwDataSize, BOOL bAnsi )
 {
   lpGroupData lpGData;
   LPDPNAME    lpName = lpData;
@@ -2508,146 +2740,263 @@ static HRESULT DP_IF_GetGroupName
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
-          ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
-            LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay2AImpl_GetGroupName( IDirectPlay2A *iface, DPID group, void *data,
+        DWORD *size )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_GetGroupName( &This->IDirectPlay4A_iface, group, data, size );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
-          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
-            LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay2Impl_GetGroupName( IDirectPlay2 *iface, DPID group, void *data,
+        DWORD *size )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
 }
 
-static HRESULT DP_IF_GetMessageCount
-          ( IDirectPlay2Impl* This, DPID idPlayer,
-            LPDWORD lpdwCount, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay3AImpl_GetGroupName( IDirectPlay3A *iface, DPID group, void *data,
+        DWORD *size )
 {
-  FIXME("(%p)->(0x%08x,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
-  return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
-                                DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
-                                bAnsi );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
-          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
+static HRESULT WINAPI IDirectPlay3Impl_GetGroupName( IDirectPlay3 *iface, DPID group, void *data,
+        DWORD *size )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
+static HRESULT WINAPI IDirectPlay4AImpl_GetGroupName( IDirectPlay4A *iface, DPID idGroup,
+        void *lpData, DWORD *lpdwDataSize )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
-          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay4Impl_GetGroupName( IDirectPlay4 *iface, DPID idGroup,
+        void *lpData, DWORD *lpdwDataSize )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay2AImpl_GetMessageCount( IDirectPlay2A *iface, DPID player,
+        DWORD *count )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_GetMessageCount( &This->IDirectPlay4A_iface, player, count );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
-          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2Impl_GetMessageCount( IDirectPlay2 *iface, DPID player,
+        DWORD *count )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3AImpl_GetMessageCount( IDirectPlay3A *iface, DPID player,
+        DWORD *count )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
 }
 
-static HRESULT DP_IF_GetPlayerData
-          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
-            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay3Impl_GetMessageCount( IDirectPlay3 *iface, DPID player,
+        DWORD *count )
 {
-  lpPlayerList lpPList;
-  DWORD dwRequiredBufferSize;
-  LPVOID lpCopyDataFrom;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
+}
 
-  TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
-         This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
+static HRESULT WINAPI IDirectPlay4AImpl_GetMessageCount( IDirectPlay4A *iface, DPID player,
+        DWORD *count )
+{
+    return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
+}
 
-  if( This->dp2->connectionInitialized == NO_PROVIDER )
-  {
-    return DPERR_UNINITIALIZED;
-  }
+static HRESULT WINAPI IDirectPlay4Impl_GetMessageCount( IDirectPlay4 *iface, DPID player,
+        DWORD *count )
+{
+    return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
+}
 
-  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
-  {
-    return DPERR_INVALIDPLAYER;
-  }
+static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerAddress( IDirectPlay2A *iface, DPID player,
+        void *data, DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4A_iface, player, data, size );
+}
 
-  /* 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;
-  }
+static HRESULT WINAPI IDirectPlay2Impl_GetPlayerAddress( IDirectPlay2 *iface, DPID player,
+        void *data, DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
+}
 
-  /* Is the user requesting to know how big a buffer is required? */
-  if( ( lpData == NULL ) ||
-      ( *lpdwDataSize < dwRequiredBufferSize )
-    )
-  {
-    *lpdwDataSize = dwRequiredBufferSize;
-    return DPERR_BUFFERTOOSMALL;
-  }
+static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerAddress( IDirectPlay3A *iface, DPID player,
+        void *data, DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
+}
 
-  CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
+static HRESULT WINAPI IDirectPlay3Impl_GetPlayerAddress( IDirectPlay3 *iface, DPID player,
+        void *data, DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
+}
 
-  return DP_OK;
+static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAddress( IDirectPlay4A *iface, DPID player,
+        void *data, DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
+    return DP_OK;
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAddress( IDirectPlay4 *iface, DPID player,
+        void *data, DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    FIXME( "(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
+    return DP_OK;
+}
+
+static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerCaps( IDirectPlay2A *iface, DPID player,
+        DPCAPS *caps, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4A_iface, player, caps, flags );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_GetPlayerCaps( IDirectPlay2 *iface, DPID player,
+        DPCAPS *caps, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerCaps( IDirectPlay3A *iface, DPID player,
+        DPCAPS *caps, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_GetPlayerCaps( IDirectPlay3 *iface, DPID player,
+        DPCAPS *caps, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
+}
+
+static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerCaps( IDirectPlay4A *iface, DPID player,
+        DPCAPS *caps, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_GetPlayerCaps( IDirectPlay4 *iface, DPID player,
+        DPCAPS *caps, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    DPSP_GETCAPSDATA data;
+
+    TRACE( "(%p)->(0x%08x,%p,0x%08x)\n", This, player, caps, flags);
+
+    if ( This->dp2->connectionInitialized == NO_PROVIDER )
+        return DPERR_UNINITIALIZED;
+
+    /* Query the service provider */
+    data.idPlayer = player;
+    data.dwFlags = flags;
+    data.lpCaps = caps;
+    data.lpISP = This->dp2->spData.lpISP;
+
+    return (*This->dp2->spData.lpCB->GetCaps)( &data );
+}
+
+static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerData( IDirectPlay2A *iface, DPID player,
+        void *data, DWORD *size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_GetPlayerData( &This->IDirectPlay4A_iface, player, data, size, flags );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_GetPlayerData( IDirectPlay2 *iface, DPID player,
+        void *data, DWORD *size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
-          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
-            LPDWORD lpdwDataSize, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerData( IDirectPlay3A *iface, DPID player,
+        void *data, DWORD *size, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
-                            dwFlags, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
-            LPDWORD lpdwDataSize, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3Impl_GetPlayerData( IDirectPlay3 *iface, DPID player,
+        void *data, DWORD *size, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
-                            dwFlags, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
 }
 
-static HRESULT DP_IF_GetPlayerName
-          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
-            LPDWORD lpdwDataSize, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerData( IDirectPlay4A *iface, DPID player,
+        void *data, DWORD *size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_GetPlayerData( IDirectPlay4 *iface, DPID player,
+        void *data, DWORD *size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    lpPlayerList plist;
+    DWORD bufsize;
+    void *src;
+
+    TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, player, data, size, flags );
+
+    if ( This->dp2->connectionInitialized == NO_PROVIDER )
+        return DPERR_UNINITIALIZED;
+
+    if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
+        return DPERR_INVALIDPLAYER;
+
+    if ( flags & DPSET_LOCAL )
+    {
+        bufsize = plist->lpPData->dwLocalDataSize;
+        src = plist->lpPData->lpLocalData;
+    }
+    else
+    {
+        bufsize = plist->lpPData->dwRemoteDataSize;
+        src = plist->lpPData->lpRemoteData;
+    }
+
+    /* Is the user requesting to know how big a buffer is required? */
+    if ( !data || *size < bufsize )
+    {
+        *size = bufsize;
+        return DPERR_BUFFERTOOSMALL;
+    }
+
+    CopyMemory( data, src, bufsize );
+
+    return DP_OK;
+}
+
+static HRESULT DP_IF_GetPlayerName( IDirectPlayImpl *This, DPID idPlayer, void *lpData,
+        DWORD *lpdwDataSize, BOOL bAnsi )
 {
   lpPlayerList lpPList;
   LPDPNAME    lpName = lpData;
@@ -2709,28 +3058,53 @@ static HRESULT DP_IF_GetPlayerName
     lpName->u2.lpszLongNameA = NULL;
   }
 
-  return DP_OK;
+  return DP_OK;
+}
+
+static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerName( IDirectPlay2A *iface, DPID player,
+        void *data, DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_GetPlayerName( &This->IDirectPlay4A_iface, player, data, size );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_GetPlayerName( IDirectPlay2 *iface, DPID player,
+        void *data, DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerName( IDirectPlay3A *iface, DPID player,
+        void *data, DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_GetPlayerName( IDirectPlay3 *iface, DPID player,
+        void *data, DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
-          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
-            LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
+        void *lpData, DWORD *lpdwDataSize )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
-            LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay4Impl_GetPlayerName( IDirectPlay4 *iface, DPID idPlayer,
+        void *lpData, DWORD *lpdwDataSize )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
 }
 
-static HRESULT DP_GetSessionDesc
-          ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
-            BOOL bAnsi )
+static HRESULT DP_GetSessionDesc( IDirectPlayImpl *This, void *lpData, DWORD *lpdwDataSize,
+        BOOL bAnsi )
 {
   DWORD dwRequiredSize;
 
@@ -2762,43 +3136,90 @@ static HRESULT DP_GetSessionDesc
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
-          ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay2AImpl_GetSessionDesc( IDirectPlay2A *iface, void *data,
+        DWORD *size )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4A_iface, data, size );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
-          ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay2Impl_GetSessionDesc( IDirectPlay2 *iface, void *data,
+        DWORD *size )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
 }
 
-/* Intended only for COM compatibility. Always returns an error. */
-static HRESULT WINAPI DirectPlay2AImpl_Initialize
-          ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
+static HRESULT WINAPI IDirectPlay3AImpl_GetSessionDesc( IDirectPlay3A *iface, void *data,
+        DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_GetSessionDesc( IDirectPlay3 *iface, void *data,
+        DWORD *size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
+}
+
+static HRESULT WINAPI IDirectPlay4AImpl_GetSessionDesc( IDirectPlay4A *iface, void *lpData,
+        DWORD *lpdwDataSize )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_GetSessionDesc( IDirectPlay4 *iface, void *lpData,
+        DWORD *lpdwDataSize )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
+}
+
+static HRESULT WINAPI IDirectPlay2AImpl_Initialize( IDirectPlay2A *iface, GUID *guid )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  TRACE("(%p)->(%p): stub\n", This, lpGUID );
-  return DPERR_ALREADYINITIALIZED;
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_Initialize( &This->IDirectPlay4A_iface, guid );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_Initialize( IDirectPlay2 *iface, GUID *guid )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_Initialize( IDirectPlay3A *iface, GUID *guid )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_Initialize( IDirectPlay3 *iface, GUID *guid )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
 }
 
 /* Intended only for COM compatibility. Always returns an error. */
-static HRESULT WINAPI DirectPlay2WImpl_Initialize
-          ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
+static HRESULT WINAPI IDirectPlay4AImpl_Initialize( IDirectPlay4A *iface, GUID *guid )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    TRACE("(%p)->(%p): no-op\n", This, guid );
+    return DPERR_ALREADYINITIALIZED;
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_Initialize( IDirectPlay4 *iface, GUID *guid )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  TRACE("(%p)->(%p): stub\n", This, lpGUID );
-  return DPERR_ALREADYINITIALIZED;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    TRACE( "(%p)->(%p): no-op\n", This, guid );
+    return DPERR_ALREADYINITIALIZED;
 }
 
 
-static HRESULT DP_SecureOpen
-          ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
-            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
-            BOOL bAnsi )
+static HRESULT DP_SecureOpen( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpsd, DWORD dwFlags,
+        const DPSECURITYDESC *lpSecurity, const DPCREDENTIALS *lpCredentials, BOOL bAnsi )
 {
   HRESULT hr = DP_OK;
 
@@ -2907,25 +3328,48 @@ static HRESULT DP_SecureOpen
   return hr;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_Open
-          ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2AImpl_Open( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
+        DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_Open( &This->IDirectPlay4A_iface, sdesc, flags );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_Open( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
+        DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_Open( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
+        DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_Open( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
+        DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
+}
+
+static HRESULT WINAPI IDirectPlay4AImpl_Open( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
+        DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
-  return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
+    return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_Open
-          ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4Impl_Open( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
+        DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
-  return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
+    return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
 }
 
-static HRESULT DP_IF_Receive
-          ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
-            DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
+static HRESULT DP_IF_Receive( IDirectPlayImpl *This, DPID *lpidFrom, DPID *lpidTo, DWORD dwFlags,
+        void *lpData, DWORD *lpdwDataSize, BOOL bAnsi )
 {
   LPDPMSG lpMsg = NULL;
 
@@ -2981,103 +3425,160 @@ static HRESULT DP_IF_Receive
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_Receive
-          ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
-            DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay2AImpl_Receive( IDirectPlay2A *iface, DPID *from, DPID *to,
+        DWORD flags, void *data, DWORD *size )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
-                        lpData, lpdwDataSize, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_Receive( &This->IDirectPlay4A_iface, from, to, flags, data, size );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_Receive
-          ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
-            DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay2Impl_Receive( IDirectPlay2 *iface, DPID *from, DPID *to,
+        DWORD flags, void *data, DWORD *size )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
-                        lpData, lpdwDataSize, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_Send
-          ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
+static HRESULT WINAPI IDirectPlay3AImpl_Receive( IDirectPlay3A *iface, DPID *from, DPID *to,
+        DWORD flags, void *data, DWORD *size )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
-                    0, 0, NULL, NULL, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_Send
-          ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
+static HRESULT WINAPI IDirectPlay3Impl_Receive( IDirectPlay3 *iface, DPID *from, DPID *to,
+        DWORD flags, void *data, DWORD *size )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
-                    0, 0, NULL, NULL, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
 }
 
-static HRESULT DP_IF_SetGroupData
-          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
-            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay4AImpl_Receive( IDirectPlay4A *iface, DPID *lpidFrom,
+        DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
 {
-  lpGroupData lpGData;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, TRUE );
+}
 
-  TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
-         This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
+static HRESULT WINAPI IDirectPlay4Impl_Receive( IDirectPlay4 *iface, DPID *lpidFrom,
+        DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, FALSE );
+}
 
-  /* Parameter check */
-  if( ( lpData == NULL ) &&
-      ( dwDataSize != 0 )
-    )
-  {
-    return DPERR_INVALIDPARAMS;
-  }
+static HRESULT WINAPI IDirectPlay2AImpl_Send( IDirectPlay2A *iface, DPID from, DPID to,
+        DWORD flags, void *data, DWORD size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_Send( &This->IDirectPlay4A_iface, from, to, flags, data, size );
+}
 
-  /* Find the pointer to the data for this player */
-  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
-  {
-    return DPERR_INVALIDOBJECT;
-  }
+static HRESULT WINAPI IDirectPlay2Impl_Send( IDirectPlay2 *iface, DPID from, DPID to,
+        DWORD flags, void *data, DWORD size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
+}
 
-  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.
-     */
-  }
+static HRESULT WINAPI IDirectPlay3AImpl_Send( IDirectPlay3A *iface, DPID from, DPID to,
+        DWORD flags, void *data, DWORD size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_Send( IDirectPlay3 *iface, DPID from, DPID to,
+        DWORD flags, void *data, DWORD size )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
+}
 
-  DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
+static HRESULT WINAPI IDirectPlay4AImpl_Send( IDirectPlay4A *iface, DPID from, DPID to,
+        DWORD flags, void *data, DWORD size )
+{
+    return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
+}
 
-  /* 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" );
-  }
+static HRESULT WINAPI IDirectPlay4Impl_Send( IDirectPlay4 *iface, DPID from, DPID to,
+        DWORD flags, void *data, DWORD size )
+{
+    return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
+}
 
-  return DP_OK;
+static HRESULT WINAPI IDirectPlay2AImpl_SetGroupData( IDirectPlay2A *iface, DPID group, void *data,
+        DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_SetGroupData( &This->IDirectPlay4A_iface, group, data, size, flags );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_SetGroupData( IDirectPlay2 *iface, DPID group, void *data,
+        DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_SetGroupData( IDirectPlay3A *iface, DPID group, void *data,
+        DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
-          ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
-            DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3Impl_SetGroupData( IDirectPlay3 *iface, DPID group, void *data,
+        DWORD size, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
-          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
-            DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4AImpl_SetGroupData( IDirectPlay4A *iface, DPID group, void *data,
+        DWORD size, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
 }
 
-static HRESULT DP_IF_SetGroupName
-          ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
-            DWORD dwFlags, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay4Impl_SetGroupData( IDirectPlay4 *iface, DPID group, void *data,
+        DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    lpGroupData gdata;
+
+    TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, group, data, size, flags );
+
+    /* Parameter check */
+    if ( !data && size )
+        return DPERR_INVALIDPARAMS;
+
+    /* Find the pointer to the data for this player */
+    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
+        return DPERR_INVALIDOBJECT;
+
+    if ( !(flags & 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( gdata, flags, data, size );
+
+    /* FIXME: Only send a message if this group is local to the session otherwise
+     * it will have been rejected above
+     */
+    if ( !(flags & DPSET_LOCAL) )
+        FIXME( "Send msg?\n" );
+
+    return DP_OK;
+}
+
+static HRESULT DP_IF_SetGroupName( IDirectPlayImpl *This, DPID idGroup, DPNAME *lpGroupName,
+        DWORD dwFlags, BOOL bAnsi )
 {
   lpGroupData lpGData;
 
@@ -3097,89 +3598,120 @@ static HRESULT DP_IF_SetGroupName
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
-          ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2AImpl_SetGroupName( IDirectPlay2A *iface, DPID group,
+        DPNAME *name, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_SetGroupName( &This->IDirectPlay4A_iface, group, name, flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
-          ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2Impl_SetGroupName( IDirectPlay2 *iface, DPID group,
+        DPNAME *name, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
 }
 
-static HRESULT DP_IF_SetPlayerData
-          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
-            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay3AImpl_SetGroupName( IDirectPlay3A *iface, DPID group,
+        DPNAME *name, DWORD flags )
 {
-  lpPlayerList lpPList;
-
-  TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
-         This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
+}
 
-  if( This->dp2->connectionInitialized == NO_PROVIDER )
-  {
-    return DPERR_UNINITIALIZED;
-  }
+static HRESULT WINAPI IDirectPlay3Impl_SetGroupName( IDirectPlay3 *iface, DPID group,
+        DPNAME *name, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
+}
 
-  /* Parameter check */
-  if( ( lpData == NULL ) &&
-      ( dwDataSize != 0 )
-    )
-  {
-    return DPERR_INVALIDPARAMS;
-  }
+static HRESULT WINAPI IDirectPlay4AImpl_SetGroupName( IDirectPlay4A *iface, DPID idGroup,
+        DPNAME *lpGroupName, DWORD dwFlags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
+}
 
-  /* Find the pointer to the data for this player */
-  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
-  {
-    return DPERR_INVALIDPLAYER;
-  }
+static HRESULT WINAPI IDirectPlay4Impl_SetGroupName( IDirectPlay4 *iface, DPID idGroup,
+        DPNAME *lpGroupName, DWORD dwFlags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
+}
 
-  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.
-     */
-  }
+static HRESULT WINAPI IDirectPlay2AImpl_SetPlayerData( IDirectPlay2A *iface, DPID player,
+        void *data, DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_SetPlayerData( &This->IDirectPlay4A_iface, player, data, size, flags );
+}
 
-  DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
+static HRESULT WINAPI IDirectPlay2Impl_SetPlayerData( IDirectPlay2 *iface, DPID player,
+        void *data, DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
+}
 
-  if( !(dwFlags & DPSET_LOCAL) )
-  {
-    FIXME( "Send msg?\n" );
-  }
+static HRESULT WINAPI IDirectPlay3AImpl_SetPlayerData( IDirectPlay3A *iface, DPID player,
+        void *data, DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
+}
 
-  return DP_OK;
+static HRESULT WINAPI IDirectPlay3Impl_SetPlayerData( IDirectPlay3 *iface, DPID player,
+        void *data, DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
-          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
-            DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerData( IDirectPlay4A *iface, DPID player,
+        void *data, DWORD size, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
-                              dwFlags, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
-            DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4Impl_SetPlayerData( IDirectPlay4 *iface, DPID player,
+        void *data, DWORD size, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
-                              dwFlags, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    lpPlayerList plist;
+
+    TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, player, data, size, flags );
+
+    if ( This->dp2->connectionInitialized == NO_PROVIDER )
+        return DPERR_UNINITIALIZED;
+
+    /* Parameter check */
+    if ( !data && size )
+        return DPERR_INVALIDPARAMS;
+
+    /* Find the pointer to the data for this player */
+    if ( (plist = DP_FindPlayer( This, player )) == NULL )
+        return DPERR_INVALIDPLAYER;
+
+    if ( !(flags & 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( plist->lpPData, flags, data, size );
+
+    if ( !(flags & DPSET_LOCAL) )
+        FIXME( "Send msg?\n" );
+
+    return DP_OK;
 }
 
-static HRESULT DP_IF_SetPlayerName
-          ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
-            DWORD dwFlags, BOOL bAnsi )
+static HRESULT DP_IF_SetPlayerName( IDirectPlayImpl *This, DPID idPlayer, DPNAME *lpPlayerName,
+        DWORD dwFlags, BOOL bAnsi )
 {
   lpPlayerList lpPList;
 
@@ -3204,25 +3736,50 @@ static HRESULT DP_IF_SetPlayerName
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
-          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2AImpl_SetPlayerName( IDirectPlay2A *iface, DPID player,
+        DPNAME *name, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_SetPlayerName( &This->IDirectPlay4A_iface, player, name, flags );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_SetPlayerName( IDirectPlay2 *iface, DPID player,
+        DPNAME *name, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_SetPlayerName( IDirectPlay3A *iface, DPID player,
+        DPNAME *name, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_SetPlayerName( IDirectPlay3 *iface, DPID player,
+        DPNAME *name, DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
+        DPNAME *lpPlayerName, DWORD dwFlags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
 }
 
-static HRESULT DP_SetSessionDesc
-          ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
-            DWORD dwFlags, BOOL bInitial, BOOL bAnsi  )
+static HRESULT WINAPI IDirectPlay4Impl_SetPlayerName( IDirectPlay4 *iface, DPID idPlayer,
+        DPNAME *lpPlayerName, DWORD dwFlags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
+}
+
+static HRESULT DP_SetSessionDesc( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpSessDesc,
+        DWORD dwFlags, BOOL bInitial, BOOL bAnsi  )
 {
   DWORD            dwRequiredSize;
   LPDPSESSIONDESC2 lpTempSessDesc;
@@ -3278,18 +3835,46 @@ static HRESULT DP_SetSessionDesc
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
-          ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay2AImpl_SetSessionDesc( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
+        DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
+    return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4A_iface, sdesc, flags );
+}
+
+static HRESULT WINAPI IDirectPlay2Impl_SetSessionDesc( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
+        DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
+    return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3AImpl_SetSessionDesc( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
+        DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_SetSessionDesc( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
+        DWORD flags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
-          ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4AImpl_SetSessionDesc( IDirectPlay4A *iface,
+        DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
-  return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_SetSessionDesc( IDirectPlay4 *iface,
+        DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
 }
 
 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
@@ -3390,68 +3975,66 @@ static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
   }
 }
 
+static HRESULT WINAPI IDirectPlay3AImpl_AddGroupToGroup( IDirectPlay3A *iface, DPID parent,
+        DPID group )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4A_iface, parent, group );
+}
 
-static HRESULT DP_IF_AddGroupToGroup
-          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
+static HRESULT WINAPI IDirectPlay3Impl_AddGroupToGroup( IDirectPlay3 *iface, DPID parent,
+        DPID group )
 {
-  lpGroupData lpGData;
-  lpGroupList lpNewGList;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
+}
 
-  TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
+static HRESULT WINAPI IDirectPlay4AImpl_AddGroupToGroup( IDirectPlay4A *iface, DPID parent,
+        DPID group )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
+}
 
-  if( This->dp2->connectionInitialized == NO_PROVIDER )
-  {
-    return DPERR_UNINITIALIZED;
-  }
+static HRESULT WINAPI IDirectPlay4Impl_AddGroupToGroup( IDirectPlay4 *iface, DPID parent,
+        DPID group )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    lpGroupData gdata;
+    lpGroupList glist;
 
-  if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
-  {
-    return DPERR_INVALIDGROUP;
-  }
+    TRACE( "(%p)->(0x%08x,0x%08x)\n", This, parent, group );
 
-  if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
-  {
-    return DPERR_INVALIDGROUP;
-  }
+    if ( This->dp2->connectionInitialized == NO_PROVIDER )
+        return DPERR_UNINITIALIZED;
 
-  /* Create a player list (ie "shortcut" ) */
-  lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
-  if( lpNewGList == NULL )
-  {
-    return DPERR_CANTADDPLAYER;
-  }
+    if ( !DP_FindAnyGroup(This, parent ) )
+        return DPERR_INVALIDGROUP;
 
-  /* Add the shortcut */
-  lpGData->uRef++;
-  lpNewGList->lpGData = lpGData;
+    if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
+        return DPERR_INVALIDGROUP;
 
-  /* Add the player to the list of players for this group */
-  DPQ_INSERT( lpGData->groups, lpNewGList, groups );
+    /* Create a player list (ie "shortcut" ) */
+    glist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *glist ) );
+    if ( !glist )
+        return DPERR_CANTADDPLAYER;
 
-  /* Send a ADDGROUPTOGROUP message */
-  FIXME( "Not sending message\n" );
+    /* Add the shortcut */
+    gdata->uRef++;
+    glist->lpGData = gdata;
 
-  return DP_OK;
-}
+    /* Add the player to the list of players for this group */
+    DPQ_INSERT( gdata->groups, glist, groups );
 
-static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
-          ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
-{
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
-}
+    /* Send a ADDGROUPTOGROUP message */
+    FIXME( "Not sending message\n" );
 
-static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
-          ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
-{
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
+    return DP_OK;
 }
 
-static HRESULT DP_IF_CreateGroupInGroup
-          ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
-            LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
-            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
+static HRESULT DP_IF_CreateGroupInGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID idParentGroup,
+        DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags,
+        BOOL bAnsi )
 {
   lpGroupData lpGParentData;
   lpGroupList lpGList;
@@ -3467,15 +4050,10 @@ static HRESULT DP_IF_CreateGroupInGroup
   }
 
   /* Verify that the specified parent is valid */
-  if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
-                                         idParentGroup ) ) == NULL
-    )
-  {
+  if( ( lpGParentData = DP_FindAnyGroup(This, idParentGroup ) ) == NULL )
     return DPERR_INVALIDGROUP;
-  }
 
-  lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
-                            dwFlags, idParentGroup, bAnsi );
+  lpGData = DP_CreateGroup(This, lpidGroup, lpGroupName, dwFlags, idParentGroup, bAnsi );
 
   if( lpGData == NULL )
   {
@@ -3534,88 +4112,102 @@ static HRESULT DP_IF_CreateGroupInGroup
     /* 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 );
+    IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
+            sizeof( msg ), 0, 0, NULL, NULL );
   }
 
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
-          ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
-            LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3AImpl_CreateGroupInGroup( IDirectPlay3A *iface, DPID parent,
+        DPID *group, DPNAME *name, void *data, DWORD size, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_CreateGroupInGroup( &This->IDirectPlay4A_iface, parent, group, name,
+            data, size, flags );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_CreateGroupInGroup( IDirectPlay3 *iface, DPID parent,
+        DPID *group, DPNAME *name, void *data, DWORD size, DWORD flags )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_CreateGroupInGroup( &This->IDirectPlay4_iface, parent, group, name,
+            data, size, flags );
+}
+
+static HRESULT WINAPI IDirectPlay4AImpl_CreateGroupInGroup( IDirectPlay4A *iface,
+        DPID idParentGroup, DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize,
+        DWORD dwFlags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
 
-  *lpidGroup = DPID_UNKNOWN;
+    *lpidGroup = DPID_UNKNOWN;
 
-  return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
-                                   lpGroupName, lpData, dwDataSize, dwFlags,
-                                   TRUE );
+    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 )
+static HRESULT WINAPI IDirectPlay4Impl_CreateGroupInGroup( IDirectPlay4 *iface, DPID idParentGroup,
+        DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
 
-  *lpidGroup = DPID_UNKNOWN;
+    *lpidGroup = DPID_UNKNOWN;
 
-  return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
-                                   lpGroupName, lpData, dwDataSize,
-                                   dwFlags, FALSE );
+    return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
+            dwDataSize, dwFlags, FALSE );
 }
 
-static HRESULT DP_IF_DeleteGroupFromGroup
-          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
+static HRESULT WINAPI IDirectPlay3AImpl_DeleteGroupFromGroup( IDirectPlay3A *iface, DPID parent,
+        DPID group )
 {
-  lpGroupList lpGList;
-  lpGroupData lpGParentData;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4A_iface, parent, group );
+}
 
-  TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
+static HRESULT WINAPI IDirectPlay3Impl_DeleteGroupFromGroup( IDirectPlay3 *iface, DPID parent,
+        DPID group )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
+}
 
-  /* Is the parent group valid? */
-  if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
-  {
-    return DPERR_INVALIDGROUP;
-  }
+static HRESULT WINAPI IDirectPlay4AImpl_DeleteGroupFromGroup( IDirectPlay4A *iface, DPID parent,
+        DPID group )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
+}
 
-  /* Remove the group from the parent group queue */
-  DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
+static HRESULT WINAPI IDirectPlay4Impl_DeleteGroupFromGroup( IDirectPlay4 *iface, DPID parent,
+        DPID group )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    lpGroupList glist;
+    lpGroupData parentdata;
 
-  if( lpGList == NULL )
-  {
-    return DPERR_INVALIDGROUP;
-  }
+    TRACE("(%p)->(0x%08x,0x%08x)\n", This, parent, group );
 
-  /* Decrement the ref count */
-  lpGList->lpGData->uRef--;
+    /* Is the parent group valid? */
+    if ( ( parentdata = DP_FindAnyGroup(This, parent ) ) == NULL )
+        return DPERR_INVALIDGROUP;
 
-  /* Free up the list item */
-  HeapFree( GetProcessHeap(), 0, lpGList );
+    /* Remove the group from the parent group queue */
+    DPQ_REMOVE_ENTRY( parentdata->groups, groups, lpGData->dpid, ==, group, glist );
 
-  /* Should send a DELETEGROUPFROMGROUP message */
-  FIXME( "message not sent\n" );
+    if ( glist == NULL )
+        return DPERR_INVALIDGROUP;
 
-  return DP_OK;
-}
+    /* Decrement the ref count */
+    glist->lpGData->uRef--;
 
-static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
-          ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
-{
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
-}
+    /* Free up the list item */
+    HeapFree( GetProcessHeap(), 0, glist );
 
-static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
-          ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
-{
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
+    /* Should send a DELETEGROUPFROMGROUP message */
+    FIXME( "message not sent\n" );
+
+    return DP_OK;
 }
 
 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
@@ -3655,10 +4247,27 @@ static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
   return TRUE;
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
-          ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3AImpl_EnumConnections( IDirectPlay3A *iface,
+        const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_EnumConnections( &This->IDirectPlay4A_iface, application, enumcb, context,
+            flags );
+}
+
+static HRESULT WINAPI IDirectPlay3Impl_EnumConnections( IDirectPlay3 *iface,
+        const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_EnumConnections( &This->IDirectPlay4_iface, application, enumcb, context,
+            flags );
+}
+
+static HRESULT WINAPI IDirectPlay4AImpl_EnumConnections( IDirectPlay4A *iface,
+        const GUID *lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, void *lpContext,
+        DWORD dwFlags )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
+  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
   TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
 
   /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
@@ -3888,102 +4497,102 @@ static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
-          ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4Impl_EnumConnections( IDirectPlay4 *iface,
+        const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(%p,%p,%p,0x%08x): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    FIXME( "(%p)->(%p,%p,%p,0x%08x): stub\n", This, application, enumcb, context, flags );
+    return DP_OK;
 }
 
-static HRESULT DP_IF_EnumGroupsInGroup
-          ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
-            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay3AImpl_EnumGroupsInGroup( IDirectPlay3A *iface, DPID group,
+        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
 {
-  lpGroupList lpGList;
-  lpGroupData lpGData;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4A_iface, group, instance,
+            enumplayercb, context, flags );
+}
 
-  FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
-         This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
-         lpContext, dwFlags, bAnsi );
+static HRESULT WINAPI IDirectPlay3Impl_EnumGroupsInGroup( IDirectPlay3 *iface, DPID group,
+        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, group, instance,
+            enumplayercb, context, flags );
+}
 
-  if( This->dp2->connectionInitialized == NO_PROVIDER )
-  {
-    return DPERR_UNINITIALIZED;
-  }
+static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupsInGroup( IDirectPlay4A *iface, DPID group,
+        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, group, instance,
+            enumplayercb, context, flags );
+}
 
-  if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
-  {
-    return DPERR_INVALIDGROUP;
-  }
+static HRESULT WINAPI IDirectPlay4Impl_EnumGroupsInGroup( IDirectPlay4 *iface, DPID group,
+        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    lpGroupList glist;
+    lpGroupData gdata;
 
-  if( DPQ_IS_EMPTY( lpGData->groups ) )
-  {
-    return DP_OK;
-  }
+    FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
+            context, flags );
 
-  lpGList = DPQ_FIRST( lpGData->groups );
+    if ( This->dp2->connectionInitialized == NO_PROVIDER )
+        return DPERR_UNINITIALIZED;
 
-  for( ;; )
-  {
-    /* FIXME: Should check dwFlags for match here */
+    if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
+        return DPERR_INVALIDGROUP;
 
-    if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
-                                    &lpGList->lpGData->name, dwFlags,
-                                    lpContext ) )
-    {
-      return DP_OK; /* User requested break */
-    }
+    if ( DPQ_IS_EMPTY( gdata->groups ) )
+        return DP_OK;
 
-    if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
-    {
-      break;
-    }
 
-    lpGList = DPQ_NEXT( lpGList->groups );
+    for( glist = DPQ_FIRST( gdata->groups ); ; glist = DPQ_NEXT( glist->groups ) )
+    {
+        /* FIXME: Should check flags for match here */
+        if ( !(*enumplayercb)( glist->lpGData->dpid, DPPLAYERTYPE_GROUP, &glist->lpGData->name,
+                    flags, context ) )
+            return DP_OK; /* User requested break */
 
-  }
+        if ( DPQ_IS_ENDOFLIST( glist->groups ) )
+            break;
+    }
 
-  return DP_OK;
+    return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
-          ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3AImpl_GetGroupConnectionSettings( IDirectPlay3A *iface,
+        DWORD flags, DPID group, void *data, DWORD *size )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
-                                  lpEnumPlayersCallback2, lpContext, dwFlags,
-                                  TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetGroupConnectionSettings( &This->IDirectPlay4A_iface, flags, group,
+            data, size );
 }
 
-static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
-          ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
-            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3Impl_GetGroupConnectionSettings( IDirectPlay3 *iface,
+        DWORD flags, DPID group, void *data, DWORD *size )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
-                                  lpEnumPlayersCallback2, lpContext, dwFlags,
-                                  FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetGroupConnectionSettings( &This->IDirectPlay4_iface, flags, group,
+            data, size );
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
-          ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay4AImpl_GetGroupConnectionSettings( IDirectPlay4A *iface,
+        DWORD flags, DPID group, void *data, DWORD *size )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
+    return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
-          ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay4Impl_GetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
+        DPID group, void *data, DWORD *size )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
+    return DP_OK;
 }
 
 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
@@ -4148,8 +4757,7 @@ static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDp
   return 0;
 }
 
-static
-HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
+static HRESULT DP_InitializeDPSP( IDirectPlayImpl *This, HMODULE hServiceProvider )
 {
   HRESULT hr;
   LPDPSP_SPINIT SPInit;
@@ -4188,8 +4796,7 @@ HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
   return hr;
 }
 
-static
-HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
+static HRESULT DP_InitializeDPLSP( IDirectPlayImpl *This, HMODULE hLobbyProvider )
 {
   HRESULT hr;
   LPSP_INIT DPLSPInit;
@@ -4229,421 +4836,443 @@ HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
   return hr;
 }
 
-static HRESULT DP_IF_InitializeConnection
-          ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay3AImpl_InitializeConnection( IDirectPlay3A *iface,
+        void *connection, DWORD flags )
 {
-  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 */
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_InitializeConnection( &This->IDirectPlay4A_iface, connection, flags );
+}
 
-  TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
+static HRESULT WINAPI IDirectPlay3Impl_InitializeConnection( IDirectPlay3 *iface,
+        void *connection, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, flags );
+}
 
-  if ( lpConnection == NULL )
-  {
-    return DPERR_INVALIDPARAMS;
-  }
+static HRESULT WINAPI IDirectPlay4AImpl_InitializeConnection( IDirectPlay4A *iface,
+        void *connection, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, flags );
+}
 
-  if( dwFlags != 0 )
-  {
-    return DPERR_INVALIDFLAGS;
-  }
+static HRESULT WINAPI IDirectPlay4Impl_InitializeConnection( IDirectPlay4 *iface,
+        void *connection, DWORD flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    HMODULE servprov;
+    GUID sp;
+    const DWORD size = 80; /* FIXME: Need to calculate it correctly */
+    BOOL is_dp_sp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
+    HRESULT hr;
 
-  if( This->dp2->connectionInitialized != NO_PROVIDER )
-  {
-    return DPERR_ALREADYINITIALIZED;
-  }
+    TRACE( "(%p)->(%p,0x%08x)\n", This, connection, flags );
 
-  /* Find out what the requested SP is and how large this buffer is */
-  hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
-                        dwAddrSize, &guidSP );
+    if ( !connection )
+        return DPERR_INVALIDPARAMS;
 
-  if( FAILED(hr) )
-  {
-    ERR( "Invalid compound address?\n" );
-    return DPERR_UNAVAILABLE;
-  }
+    if ( flags )
+        return DPERR_INVALIDFLAGS;
 
-  /* Load the service provider */
-  hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
+    if ( This->dp2->connectionInitialized != NO_PROVIDER )
+        return DPERR_ALREADYINITIALIZED;
 
-  if( hServiceProvider == 0 )
-  {
-    ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
-    return DPERR_UNAVAILABLE;
-  }
+    /* Find out what the requested SP is and how large this buffer is */
+    hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, connection, size, &sp );
 
-  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;
+    if ( FAILED(hr) )
+    {
+        ERR( "Invalid compound address?\n" );
+        return DPERR_UNAVAILABLE;
+    }
 
-     hr = DP_InitializeDPSP( This, hServiceProvider );
-  }
-  else
-  {
-     This->dp2->dplspData.lpAddress = lpConnection;
+    /* Load the service provider */
+    servprov = DP_LoadSP( &sp, &This->dp2->spData, &is_dp_sp );
 
-     hr = DP_InitializeDPLSP( This, hServiceProvider );
-  }
+    if ( !servprov )
+    {
+        ERR( "Unable to load service provider %s\n", debugstr_guid(&sp) );
+        return DPERR_UNAVAILABLE;
+    }
 
-  if( FAILED(hr) )
-  {
-    return hr;
-  }
+    if ( is_dp_sp )
+    {
+         /* Fill in what we can of the Service Provider required information.
+          * The rest was be done in DP_LoadSP
+          */
+         This->dp2->spData.lpAddress = connection;
+         This->dp2->spData.dwAddressSize = size;
+         This->dp2->spData.lpGuid = &sp;
+         hr = DP_InitializeDPSP( This, servprov );
+    }
+    else
+    {
+         This->dp2->dplspData.lpAddress = connection;
+         hr = DP_InitializeDPLSP( This, servprov );
+    }
 
-  return DP_OK;
+    if ( FAILED(hr) )
+        return hr;
+
+    return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
-          ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay3AImpl_SecureOpen( IDirectPlay3A *iface,
+        const DPSESSIONDESC2 *sdesc, DWORD flags, const DPSECURITYDESC *security,
+        const DPCREDENTIALS *credentials )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_SecureOpen( &This->IDirectPlay4A_iface, sdesc, flags, security,
+            credentials );
+}
 
-  /* This may not be externally invoked once either an SP or LP is initialized */
-  if( This->dp2->connectionInitialized != NO_PROVIDER )
-  {
-    return DPERR_ALREADYINITIALIZED;
-  }
+static HRESULT WINAPI IDirectPlay3Impl_SecureOpen( IDirectPlay3 *iface,
+        const DPSESSIONDESC2 *sdesc, DWORD flags, const DPSECURITYDESC *security,
+        const DPCREDENTIALS *credentials )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_SecureOpen( &This->IDirectPlay4_iface, sdesc, flags, security,
+            credentials );
+}
 
-  return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
+static HRESULT WINAPI IDirectPlay4AImpl_SecureOpen( IDirectPlay4A *iface,
+        const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
+        const DPCREDENTIALS *lpCredentials )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
 }
 
-static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
-          ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4Impl_SecureOpen( IDirectPlay4 *iface,
+        const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
+        const DPCREDENTIALS *lpCredentials )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
+}
 
-  /* This may not be externally invoked once either an SP or LP is initialized */
-  if( This->dp2->connectionInitialized != NO_PROVIDER )
-  {
-    return DPERR_ALREADYINITIALIZED;
-  }
+static HRESULT WINAPI IDirectPlay3AImpl_SendChatMessage( IDirectPlay3A *iface, DPID from, DPID to,
+        DWORD flags, DPCHAT *chatmsg )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_SendChatMessage( &This->IDirectPlay4A_iface, from, to, flags, chatmsg );
+}
 
-  return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
+static HRESULT WINAPI IDirectPlay3Impl_SendChatMessage( IDirectPlay3 *iface, DPID from, DPID to,
+        DWORD flags, DPCHAT *chatmsg )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_SendChatMessage( &This->IDirectPlay4_iface, from, to, flags, chatmsg );
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
-          ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
-            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
+static HRESULT WINAPI IDirectPlay4AImpl_SendChatMessage( IDirectPlay4A *iface, DPID from,
+        DPID to, DWORD flags, DPCHAT *chatmsg )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
-  return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
+    return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
-          ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
-            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
+static HRESULT WINAPI IDirectPlay4Impl_SendChatMessage( IDirectPlay4 *iface, DPID from, DPID to,
+        DWORD flags, DPCHAT *chatmsg )
 {
-  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
-  return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
+    return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
-          ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
+static HRESULT WINAPI IDirectPlay3AImpl_SetGroupConnectionSettings( IDirectPlay3A *iface,
+        DWORD flags, DPID group, DPLCONNECTION *connection )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_SetGroupConnectionSettings( &This->IDirectPlay4A_iface, flags, group,
+            connection );
 }
 
-static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
-          ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
+static HRESULT WINAPI IDirectPlay3Impl_SetGroupConnectionSettings( IDirectPlay3 *iface,
+        DWORD flags, DPID group, DPLCONNECTION *connection )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_SetGroupConnectionSettings( &This->IDirectPlay4_iface, flags, group,
+            connection );
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
-          ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
+static HRESULT WINAPI IDirectPlay4AImpl_SetGroupConnectionSettings( IDirectPlay4A *iface,
+        DWORD flags, DPID group, DPLCONNECTION *connection )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
+    return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
-          ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
+static HRESULT WINAPI IDirectPlay4Impl_SetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
+        DPID group, DPLCONNECTION *connection )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    FIXME( "(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
+    return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_StartSession
-          ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
+static HRESULT WINAPI IDirectPlay3AImpl_StartSession( IDirectPlay3A *iface, DWORD flags,
+        DPID group )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_StartSession( &This->IDirectPlay4A_iface, flags, group );
 }
 
-static HRESULT WINAPI DirectPlay3WImpl_StartSession
-          ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
+static HRESULT WINAPI IDirectPlay3Impl_StartSession( IDirectPlay3 *iface, DWORD flags,
+        DPID group )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_StartSession( &This->IDirectPlay4_iface, flags, group );
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
-          ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
+static HRESULT WINAPI IDirectPlay4AImpl_StartSession( IDirectPlay4A *iface, DWORD flags,
+        DPID group )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_StartSession( &This->IDirectPlay4_iface, flags, group );
 }
 
-static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
-          ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
+static HRESULT WINAPI IDirectPlay4Impl_StartSession( IDirectPlay4 *iface, DWORD flags, DPID group )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, flags, group );
+    return DP_OK;
 }
 
-static HRESULT DP_IF_GetGroupParent
-          ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
-            BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay3AImpl_GetGroupFlags( IDirectPlay3A *iface, DPID group,
+        DWORD *flags )
 {
-  lpGroupData lpGData;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4A_iface, group, flags );
+}
 
-  TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
+static HRESULT WINAPI IDirectPlay3Impl_GetGroupFlags( IDirectPlay3 *iface, DPID group,
+        DWORD *flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4_iface, group, flags );
+}
 
-  if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
-  {
-    return DPERR_INVALIDGROUP;
-  }
+static HRESULT WINAPI IDirectPlay4AImpl_GetGroupFlags( IDirectPlay4A *iface, DPID group,
+        DWORD *flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4_iface, group, flags );
+}
 
-  *lpidGroup = lpGData->dpid;
+static HRESULT WINAPI IDirectPlay4Impl_GetGroupFlags( IDirectPlay4 *iface, DPID group,
+        DWORD *flags )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, flags );
+    return DP_OK;
+}
 
-  return DP_OK;
+static HRESULT WINAPI IDirectPlay3AImpl_GetGroupParent( IDirectPlay3A *iface, DPID group,
+        DPID *parent )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetGroupParent( &This->IDirectPlay4A_iface, group, parent );
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
-          ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
+static HRESULT WINAPI IDirectPlay3Impl_GetGroupParent( IDirectPlay3 *iface, DPID group,
+        DPID *parent )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetGroupParent( &This->IDirectPlay4_iface, group, parent );
 }
-static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
-          ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
+
+static HRESULT WINAPI IDirectPlay4AImpl_GetGroupParent( IDirectPlay4A *iface, DPID group,
+        DPID *parent )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_GetGroupParent( &This->IDirectPlay4_iface, group, parent );
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
-          ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay4Impl_GetGroupParent( IDirectPlay4 *iface, DPID group,
+        DPID *parent )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    lpGroupData gdata;
+
+    TRACE( "(%p)->(0x%08x,%p)\n", This, group, parent );
+
+    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
+        return DPERR_INVALIDGROUP;
+
+    *parent = gdata->dpid;
+
+    return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
-          ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerAccount( IDirectPlay3A *iface, DPID player,
+        DWORD flags, void *data, DWORD *size )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetPlayerAccount( &This->IDirectPlay4A_iface, player, flags, data, size );
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
-          ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
+static HRESULT WINAPI IDirectPlay3Impl_GetPlayerAccount( IDirectPlay3 *iface, DPID player,
+        DWORD flags, void *data, DWORD *size )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetPlayerAccount( &This->IDirectPlay4_iface, player, flags, data, size );
 }
 
-static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
-          ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
+static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAccount( IDirectPlay4A *iface, DPID player,
+        DWORD flags, void *data, DWORD *size )
 {
-  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
-  FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
+    return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
-          ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
+static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAccount( IDirectPlay4 *iface, DPID player,
+        DWORD flags, void *data, DWORD *size )
 {
-  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
-  FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
+    return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
-          ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
+static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerFlags( IDirectPlay3A *iface, DPID player,
+        DWORD *flags )
 {
-  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
-  FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
+    return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4A_iface, player, flags );
 }
 
-static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
-          ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
+static HRESULT WINAPI IDirectPlay3Impl_GetPlayerFlags( IDirectPlay3 *iface, DPID player,
+        DWORD *flags )
 {
-  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
+    return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4_iface, player, flags );
 }
 
-static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
-          ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
+static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerFlags( IDirectPlay4A *iface, DPID player,
+        DWORD *flags )
 {
-  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
-  FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
-  return DP_OK;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4_iface, player, flags );
 }
 
-static HRESULT 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 IDirectPlay4Impl_GetPlayerFlags( IDirectPlay4 *iface, DPID player,
+        DWORD *flags )
 {
-  BOOL         bValidDestination = FALSE;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, flags );
+    return DP_OK;
+}
 
-  FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
-         ": stub\n",
-         This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
-         dwTimeout, lpContext, lpdwMsgID, bAnsi );
+static HRESULT WINAPI IDirectPlay4AImpl_GetGroupOwner( IDirectPlay4A *iface, DPID group,
+        DPID *owner )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_GetGroupOwner( &This->IDirectPlay4_iface, group, owner );
+}
 
-  if( This->dp2->connectionInitialized == NO_PROVIDER )
-  {
-    return DPERR_UNINITIALIZED;
-  }
+static HRESULT WINAPI IDirectPlay4Impl_GetGroupOwner( IDirectPlay4 *iface, DPID group,
+        DPID *owner )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, owner );
+    return DP_OK;
+}
 
-  /* FIXME: Add parameter checking */
-  /* FIXME: First call to this needs to acquire a message id which will be
-   *        used for multiple sends
-   */
+static HRESULT WINAPI IDirectPlay4AImpl_SetGroupOwner( IDirectPlay4A *iface, DPID group,
+        DPID owner )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_SetGroupOwner( &This->IDirectPlay4_iface, group, owner );
+}
+
+static HRESULT WINAPI IDirectPlay4Impl_SetGroupOwner( IDirectPlay4 *iface, DPID group ,
+        DPID owner )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, owner );
+    return DP_OK;
+}
 
-  /* NOTE: Can't send messages to yourself - this will be trapped in receive */
+static HRESULT WINAPI IDirectPlay4AImpl_SendEx( IDirectPlay4A *iface, DPID from, DPID to,
+        DWORD flags, void *data, DWORD size, DWORD priority, DWORD timeout, void *context,
+        DWORD *msgid )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_SendEx( &This->IDirectPlay4_iface, from, to, flags, data, size, priority,
+            timeout, context, msgid );
+}
 
-  /* 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( DP_FindPlayer( This, idFrom ) == NULL )
-    {
-      WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
-      return DPERR_INVALIDPLAYER;
-    }
-  }
+static HRESULT WINAPI IDirectPlay4Impl_SendEx( IDirectPlay4 *iface, DPID from, DPID to,
+        DWORD flags, void *data, DWORD size, DWORD priority, DWORD timeout, void *context,
+        DWORD *msgid )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
 
-  /* 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;
+    FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p): semi-stub\n",
+            This, from, to, flags, data, size, priority, timeout, context, msgid );
 
-    /* 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 ( This->dp2->connectionInitialized == NO_PROVIDER )
+        return DPERR_UNINITIALIZED;
 
-  if( ( !bValidDestination ) &&
-      ( DP_FindPlayer( This, idTo ) != NULL )
-    )
-  {
-    /* 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 );
-  }
+    /* FIXME: Add parameter checking */
+    /* FIXME: First call to this needs to acquire a message id which will be
+     *        used for multiple sends
+     */
 
-  if( ( !bValidDestination ) &&
-      ( DP_FindAnyGroup( This, idTo ) != NULL )
-    )
-  {
-    bValidDestination = TRUE;
+    /* NOTE: Can't send messages to yourself - this will be trapped in receive */
 
-    /* See if SP has the ability to multicast. If so, use it */
-    if( This->dp2->spData.lpCB->SendToGroupEx )
+    /* Verify that the message is being sent from a valid local player. The
+     * from player may be anonymous DPID_UNKNOWN
+     */
+    if ( from != DPID_UNKNOWN && !DP_FindPlayer( This, from ) )
     {
-      FIXME( "Use group sendex\n" );
+        WARN( "INFO: Invalid from player 0x%08x\n", from );
+        return DPERR_INVALIDPLAYER;
     }
-    else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
+
+    /* 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 ( to == DPID_ALLPLAYERS )
     {
-      FIXME( "Use obsolete group send to group\n" );
+        /* 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 */
+            FIXME( "Send to all players using EnumPlayersInGroup\n" );
     }
-    else /* No multicast, multiplicate */
+    else if ( DP_FindPlayer( This, to ) )
     {
-      FIXME( "Send to all players using EnumPlayersInGroup\n" );
+        /* Have the service provider send this message */
+        /* FIXME: Could optimize for local interface sends */
+        return DP_SP_SendEx( This, flags, data, size, priority, timeout, context, msgid );
     }
-
-#if 0
-    if( bExpectReply )
+    else if ( DP_FindAnyGroup( This, to ) )
     {
-      DWORD dwWaitReturn;
+        /* 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" );
 
-      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
-  }
+    else
+        return DPERR_INVALIDPLAYER;
 
-  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 DP_SP_SendEx
-          ( IDirectPlay2Impl* This, DWORD dwFlags,
-            LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
-            LPVOID lpContext, LPDWORD lpdwMsgID )
+static HRESULT DP_SP_SendEx( IDirectPlayImpl *This, DWORD dwFlags, void *lpData, DWORD dwDataSize,
+        DWORD dwPriority, DWORD dwTimeout, void *lpContext, DWORD *lpdwMsgID )
 {
   LPDPMSG lpMElem;
 
@@ -4662,511 +5291,445 @@ static HRESULT DP_SP_SendEx
   return DP_OK;
 }
 
-static HRESULT DP_IF_GetMessageQueue
-          ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
-            LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
+static HRESULT WINAPI IDirectPlay4AImpl_GetMessageQueue( IDirectPlay4A *iface, DPID from, DPID to,
+        DWORD flags, DWORD *msgs, DWORD *bytes )
 {
-  HRESULT hr = DP_OK;
-
-  FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%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? */
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_GetMessageQueue( &This->IDirectPlay4_iface, from, to, flags, msgs, bytes );
+}
 
-  if( This->dp2->spData.lpCB->GetMessageQueue )
-  {
-    DPSP_GETMESSAGEQUEUEDATA data;
+static HRESULT WINAPI IDirectPlay4Impl_GetMessageQueue( IDirectPlay4 *iface, DPID from, DPID to,
+        DWORD flags, DWORD *msgs, DWORD *bytes )
+{
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
+    HRESULT hr = DP_OK;
 
-    FIXME( "Calling SP GetMessageQueue - is it right?\n" );
+    FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p): semi-stub\n", This, from, to, flags, msgs, bytes );
 
-    /* FIXME: None of this is documented :( */
+    /* FIXME: Do we need to do from and to sanity checking here? */
+    /* FIXME: What about sends which are not immediate? */
 
-    data.lpISP        = This->dp2->spData.lpISP;
-    data.dwFlags      = dwFlags;
-    data.idFrom       = idFrom;
-    data.idTo         = idTo;
-    data.lpdwNumMsgs  = lpdwNumMsgs;
-    data.lpdwNumBytes = lpdwNumBytes;
+    if ( This->dp2->spData.lpCB->GetMessageQueue )
+    {
+        DPSP_GETMESSAGEQUEUEDATA data;
 
-    hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
-  }
-  else
-  {
-    FIXME( "No SP for GetMessageQueue - fake some data\n" );
-  }
+        FIXME( "Calling SP GetMessageQueue - is it right?\n" );
 
-  return hr;
-}
+        /* FIXME: None of this is documented :( */
+        data.lpISP        = This->dp2->spData.lpISP;
+        data.dwFlags      = flags;
+        data.idFrom       = from;
+        data.idTo         = to;
+        data.lpdwNumMsgs  = msgs;
+        data.lpdwNumBytes = bytes;
 
-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 );
-}
+        hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
+    }
+    else
+        FIXME( "No SP for GetMessageQueue - fake some data\n" );
 
-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 );
+    return hr;
 }
 
-static HRESULT DP_IF_CancelMessage
-          ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
-            DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
+static HRESULT dplay_cancelmsg ( IDirectPlayImpl* This, DWORD msgid, DWORD flags, DWORD minprio,
+        DWORD maxprio )
 {
-  HRESULT hr = DP_OK;
+    HRESULT hr = DP_OK;
 
-  FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
-         This, dwMsgID, dwFlags, bAnsi );
+    FIXME( "(%p)->(0x%08x,0x%08x): semi stub\n", This, msgid, flags );
 
-  if( This->dp2->spData.lpCB->Cancel )
-  {
-    DPSP_CANCELDATA data;
+    if ( This->dp2->spData.lpCB->Cancel )
+    {
+        DPSP_CANCELDATA data;
 
-    TRACE( "Calling SP Cancel\n" );
+        TRACE( "Calling SP Cancel\n" );
 
-    /* FIXME: Undocumented callback */
+        /* FIXME: Undocumented callback */
 
-    data.lpISP          = This->dp2->spData.lpISP;
-    data.dwFlags        = dwFlags;
-    data.lprglpvSPMsgID = NULL;
-    data.cSPMsgID       = dwMsgID;
-    data.dwMinPriority  = dwMinPriority;
-    data.dwMaxPriority  = dwMaxPriority;
+        data.lpISP          = This->dp2->spData.lpISP;
+        data.dwFlags        = flags;
+        data.lprglpvSPMsgID = NULL;
+        data.cSPMsgID       = msgid;
+        data.dwMinPriority  = minprio;
+        data.dwMaxPriority  = maxprio;
 
-    hr = (*This->dp2->spData.lpCB->Cancel)( &data );
-  }
-  else
-  {
-    FIXME( "SP doesn't implement Cancel\n" );
-  }
+        hr = (*This->dp2->spData.lpCB->Cancel)( &data );
+    }
+    else
+        FIXME( "SP doesn't implement Cancel\n" );
 
-  return hr;
+    return hr;
 }
 
-static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
-          ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4AImpl_CancelMessage( IDirectPlay4A *iface, DWORD msgid,
+        DWORD flags )
 {
-  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 );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_CancelMessage( &This->IDirectPlay4_iface, msgid, flags );
 }
 
-static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
-          ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4Impl_CancelMessage( IDirectPlay4 *iface, DWORD msgid,
+        DWORD flags )
 {
-  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
 
-  if( dwFlags != 0 )
-  {
-    return DPERR_INVALIDFLAGS;
-  }
+    if ( flags != 0 )
+      return DPERR_INVALIDFLAGS;
 
-  if( dwMsgID == 0 )
-  {
-    dwFlags |= DPCANCELSEND_ALL;
-  }
+    if ( msgid == 0 )
+      flags |= DPCANCELSEND_ALL;
 
-  return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
+    return dplay_cancelmsg( This, msgid, flags, 0, 0 );
 }
 
-static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
-          ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4AImpl_CancelPriority( IDirectPlay4A *iface, DWORD minprio,
+        DWORD maxprio, DWORD flags )
 {
-  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
-
-  if( dwFlags != 0 )
-  {
-    return DPERR_INVALIDFLAGS;
-  }
-
-  return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
-                              dwMaxPriority, TRUE );
+    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
+    return IDirectPlayX_CancelPriority( &This->IDirectPlay4_iface, minprio, maxprio, flags );
 }
 
-static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
-          ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
-            DWORD dwFlags )
+static HRESULT WINAPI IDirectPlay4Impl_CancelPriority( IDirectPlay4 *iface, DWORD minprio,
+        DWORD maxprio, DWORD flags )
 {
-  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
+    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
 
-  if( dwFlags != 0 )
-  {
-    return DPERR_INVALIDFLAGS;
-  }
+    if ( flags != 0 )
+        return DPERR_INVALIDFLAGS;
 
-  return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
-                              dwMaxPriority, FALSE );
+    return dplay_cancelmsg( This, 0, DPCANCELSEND_PRIORITY, minprio, maxprio );
 }
 
-/* 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
+static const IDirectPlay2Vtbl dp2_vt =
+{
+    IDirectPlay2Impl_QueryInterface,
+    IDirectPlay2Impl_AddRef,
+    IDirectPlay2Impl_Release,
+    IDirectPlay2Impl_AddPlayerToGroup,
+    IDirectPlay2Impl_Close,
+    IDirectPlay2Impl_CreateGroup,
+    IDirectPlay2Impl_CreatePlayer,
+    IDirectPlay2Impl_DeletePlayerFromGroup,
+    IDirectPlay2Impl_DestroyGroup,
+    IDirectPlay2Impl_DestroyPlayer,
+    IDirectPlay2Impl_EnumGroupPlayers,
+    IDirectPlay2Impl_EnumGroups,
+    IDirectPlay2Impl_EnumPlayers,
+    IDirectPlay2Impl_EnumSessions,
+    IDirectPlay2Impl_GetCaps,
+    IDirectPlay2Impl_GetGroupData,
+    IDirectPlay2Impl_GetGroupName,
+    IDirectPlay2Impl_GetMessageCount,
+    IDirectPlay2Impl_GetPlayerAddress,
+    IDirectPlay2Impl_GetPlayerCaps,
+    IDirectPlay2Impl_GetPlayerData,
+    IDirectPlay2Impl_GetPlayerName,
+    IDirectPlay2Impl_GetSessionDesc,
+    IDirectPlay2Impl_Initialize,
+    IDirectPlay2Impl_Open,
+    IDirectPlay2Impl_Receive,
+    IDirectPlay2Impl_Send,
+    IDirectPlay2Impl_SetGroupData,
+    IDirectPlay2Impl_SetGroupName,
+    IDirectPlay2Impl_SetPlayerData,
+    IDirectPlay2Impl_SetPlayerName,
+    IDirectPlay2Impl_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
+static const IDirectPlay2Vtbl dp2A_vt =
+{
+    IDirectPlay2AImpl_QueryInterface,
+    IDirectPlay2AImpl_AddRef,
+    IDirectPlay2AImpl_Release,
+    IDirectPlay2AImpl_AddPlayerToGroup,
+    IDirectPlay2AImpl_Close,
+    IDirectPlay2AImpl_CreateGroup,
+    IDirectPlay2AImpl_CreatePlayer,
+    IDirectPlay2AImpl_DeletePlayerFromGroup,
+    IDirectPlay2AImpl_DestroyGroup,
+    IDirectPlay2AImpl_DestroyPlayer,
+    IDirectPlay2AImpl_EnumGroupPlayers,
+    IDirectPlay2AImpl_EnumGroups,
+    IDirectPlay2AImpl_EnumPlayers,
+    IDirectPlay2AImpl_EnumSessions,
+    IDirectPlay2AImpl_GetCaps,
+    IDirectPlay2AImpl_GetGroupData,
+    IDirectPlay2AImpl_GetGroupName,
+    IDirectPlay2AImpl_GetMessageCount,
+    IDirectPlay2AImpl_GetPlayerAddress,
+    IDirectPlay2AImpl_GetPlayerCaps,
+    IDirectPlay2AImpl_GetPlayerData,
+    IDirectPlay2AImpl_GetPlayerName,
+    IDirectPlay2AImpl_GetSessionDesc,
+    IDirectPlay2AImpl_Initialize,
+    IDirectPlay2AImpl_Open,
+    IDirectPlay2AImpl_Receive,
+    IDirectPlay2AImpl_Send,
+    IDirectPlay2AImpl_SetGroupData,
+    IDirectPlay2AImpl_SetGroupName,
+    IDirectPlay2AImpl_SetPlayerData,
+    IDirectPlay2AImpl_SetPlayerName,
+    IDirectPlay2AImpl_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 dp3_vt =
+{
+    IDirectPlay3Impl_QueryInterface,
+    IDirectPlay3Impl_AddRef,
+    IDirectPlay3Impl_Release,
+    IDirectPlay3Impl_AddPlayerToGroup,
+    IDirectPlay3Impl_Close,
+    IDirectPlay3Impl_CreateGroup,
+    IDirectPlay3Impl_CreatePlayer,
+    IDirectPlay3Impl_DeletePlayerFromGroup,
+    IDirectPlay3Impl_DestroyGroup,
+    IDirectPlay3Impl_DestroyPlayer,
+    IDirectPlay3Impl_EnumGroupPlayers,
+    IDirectPlay3Impl_EnumGroups,
+    IDirectPlay3Impl_EnumPlayers,
+    IDirectPlay3Impl_EnumSessions,
+    IDirectPlay3Impl_GetCaps,
+    IDirectPlay3Impl_GetGroupData,
+    IDirectPlay3Impl_GetGroupName,
+    IDirectPlay3Impl_GetMessageCount,
+    IDirectPlay3Impl_GetPlayerAddress,
+    IDirectPlay3Impl_GetPlayerCaps,
+    IDirectPlay3Impl_GetPlayerData,
+    IDirectPlay3Impl_GetPlayerName,
+    IDirectPlay3Impl_GetSessionDesc,
+    IDirectPlay3Impl_Initialize,
+    IDirectPlay3Impl_Open,
+    IDirectPlay3Impl_Receive,
+    IDirectPlay3Impl_Send,
+    IDirectPlay3Impl_SetGroupData,
+    IDirectPlay3Impl_SetGroupName,
+    IDirectPlay3Impl_SetPlayerData,
+    IDirectPlay3Impl_SetPlayerName,
+    IDirectPlay3Impl_SetSessionDesc,
+    IDirectPlay3Impl_AddGroupToGroup,
+    IDirectPlay3Impl_CreateGroupInGroup,
+    IDirectPlay3Impl_DeleteGroupFromGroup,
+    IDirectPlay3Impl_EnumConnections,
+    IDirectPlay3Impl_EnumGroupsInGroup,
+    IDirectPlay3Impl_GetGroupConnectionSettings,
+    IDirectPlay3Impl_InitializeConnection,
+    IDirectPlay3Impl_SecureOpen,
+    IDirectPlay3Impl_SendChatMessage,
+    IDirectPlay3Impl_SetGroupConnectionSettings,
+    IDirectPlay3Impl_StartSession,
+    IDirectPlay3Impl_GetGroupFlags,
+    IDirectPlay3Impl_GetGroupParent,
+    IDirectPlay3Impl_GetPlayerAccount,
+    IDirectPlay3Impl_GetPlayerFlags
+};
 
-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
+static const IDirectPlay3Vtbl dp3A_vt =
+{
+    IDirectPlay3AImpl_QueryInterface,
+    IDirectPlay3AImpl_AddRef,
+    IDirectPlay3AImpl_Release,
+    IDirectPlay3AImpl_AddPlayerToGroup,
+    IDirectPlay3AImpl_Close,
+    IDirectPlay3AImpl_CreateGroup,
+    IDirectPlay3AImpl_CreatePlayer,
+    IDirectPlay3AImpl_DeletePlayerFromGroup,
+    IDirectPlay3AImpl_DestroyGroup,
+    IDirectPlay3AImpl_DestroyPlayer,
+    IDirectPlay3AImpl_EnumGroupPlayers,
+    IDirectPlay3AImpl_EnumGroups,
+    IDirectPlay3AImpl_EnumPlayers,
+    IDirectPlay3AImpl_EnumSessions,
+    IDirectPlay3AImpl_GetCaps,
+    IDirectPlay3AImpl_GetGroupData,
+    IDirectPlay3AImpl_GetGroupName,
+    IDirectPlay3AImpl_GetMessageCount,
+    IDirectPlay3AImpl_GetPlayerAddress,
+    IDirectPlay3AImpl_GetPlayerCaps,
+    IDirectPlay3AImpl_GetPlayerData,
+    IDirectPlay3AImpl_GetPlayerName,
+    IDirectPlay3AImpl_GetSessionDesc,
+    IDirectPlay3AImpl_Initialize,
+    IDirectPlay3AImpl_Open,
+    IDirectPlay3AImpl_Receive,
+    IDirectPlay3AImpl_Send,
+    IDirectPlay3AImpl_SetGroupData,
+    IDirectPlay3AImpl_SetGroupName,
+    IDirectPlay3AImpl_SetPlayerData,
+    IDirectPlay3AImpl_SetPlayerName,
+    IDirectPlay3AImpl_SetSessionDesc,
+    IDirectPlay3AImpl_AddGroupToGroup,
+    IDirectPlay3AImpl_CreateGroupInGroup,
+    IDirectPlay3AImpl_DeleteGroupFromGroup,
+    IDirectPlay3AImpl_EnumConnections,
+    IDirectPlay3AImpl_EnumGroupsInGroup,
+    IDirectPlay3AImpl_GetGroupConnectionSettings,
+    IDirectPlay3AImpl_InitializeConnection,
+    IDirectPlay3AImpl_SecureOpen,
+    IDirectPlay3AImpl_SendChatMessage,
+    IDirectPlay3AImpl_SetGroupConnectionSettings,
+    IDirectPlay3AImpl_StartSession,
+    IDirectPlay3AImpl_GetGroupFlags,
+    IDirectPlay3AImpl_GetGroupParent,
+    IDirectPlay3AImpl_GetPlayerAccount,
+    IDirectPlay3AImpl_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
+static const IDirectPlay4Vtbl dp4_vt =
+{
+    IDirectPlay4Impl_QueryInterface,
+    IDirectPlay4Impl_AddRef,
+    IDirectPlay4Impl_Release,
+    IDirectPlay4Impl_AddPlayerToGroup,
+    IDirectPlay4Impl_Close,
+    IDirectPlay4Impl_CreateGroup,
+    IDirectPlay4Impl_CreatePlayer,
+    IDirectPlay4Impl_DeletePlayerFromGroup,
+    IDirectPlay4Impl_DestroyGroup,
+    IDirectPlay4Impl_DestroyPlayer,
+    IDirectPlay4Impl_EnumGroupPlayers,
+    IDirectPlay4Impl_EnumGroups,
+    IDirectPlay4Impl_EnumPlayers,
+    IDirectPlay4Impl_EnumSessions,
+    IDirectPlay4Impl_GetCaps,
+    IDirectPlay4Impl_GetGroupData,
+    IDirectPlay4Impl_GetGroupName,
+    IDirectPlay4Impl_GetMessageCount,
+    IDirectPlay4Impl_GetPlayerAddress,
+    IDirectPlay4Impl_GetPlayerCaps,
+    IDirectPlay4Impl_GetPlayerData,
+    IDirectPlay4Impl_GetPlayerName,
+    IDirectPlay4Impl_GetSessionDesc,
+    IDirectPlay4Impl_Initialize,
+    IDirectPlay4Impl_Open,
+    IDirectPlay4Impl_Receive,
+    IDirectPlay4Impl_Send,
+    IDirectPlay4Impl_SetGroupData,
+    IDirectPlay4Impl_SetGroupName,
+    IDirectPlay4Impl_SetPlayerData,
+    IDirectPlay4Impl_SetPlayerName,
+    IDirectPlay4Impl_SetSessionDesc,
+    IDirectPlay4Impl_AddGroupToGroup,
+    IDirectPlay4Impl_CreateGroupInGroup,
+    IDirectPlay4Impl_DeleteGroupFromGroup,
+    IDirectPlay4Impl_EnumConnections,
+    IDirectPlay4Impl_EnumGroupsInGroup,
+    IDirectPlay4Impl_GetGroupConnectionSettings,
+    IDirectPlay4Impl_InitializeConnection,
+    IDirectPlay4Impl_SecureOpen,
+    IDirectPlay4Impl_SendChatMessage,
+    IDirectPlay4Impl_SetGroupConnectionSettings,
+    IDirectPlay4Impl_StartSession,
+    IDirectPlay4Impl_GetGroupFlags,
+    IDirectPlay4Impl_GetGroupParent,
+    IDirectPlay4Impl_GetPlayerAccount,
+    IDirectPlay4Impl_GetPlayerFlags,
+    IDirectPlay4Impl_GetGroupOwner,
+    IDirectPlay4Impl_SetGroupOwner,
+    IDirectPlay4Impl_SendEx,
+    IDirectPlay4Impl_GetMessageQueue,
+    IDirectPlay4Impl_CancelMessage,
+    IDirectPlay4Impl_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(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
+static const IDirectPlay4Vtbl dp4A_vt =
+{
+    IDirectPlay4AImpl_QueryInterface,
+    IDirectPlay4AImpl_AddRef,
+    IDirectPlay4AImpl_Release,
+    IDirectPlay4AImpl_AddPlayerToGroup,
+    IDirectPlay4AImpl_Close,
+    IDirectPlay4AImpl_CreateGroup,
+    IDirectPlay4AImpl_CreatePlayer,
+    IDirectPlay4AImpl_DeletePlayerFromGroup,
+    IDirectPlay4AImpl_DestroyGroup,
+    IDirectPlay4AImpl_DestroyPlayer,
+    IDirectPlay4AImpl_EnumGroupPlayers,
+    IDirectPlay4AImpl_EnumGroups,
+    IDirectPlay4AImpl_EnumPlayers,
+    IDirectPlay4AImpl_EnumSessions,
+    IDirectPlay4AImpl_GetCaps,
+    IDirectPlay4AImpl_GetGroupData,
+    IDirectPlay4AImpl_GetGroupName,
+    IDirectPlay4AImpl_GetMessageCount,
+    IDirectPlay4AImpl_GetPlayerAddress,
+    IDirectPlay4AImpl_GetPlayerCaps,
+    IDirectPlay4AImpl_GetPlayerData,
+    IDirectPlay4AImpl_GetPlayerName,
+    IDirectPlay4AImpl_GetSessionDesc,
+    IDirectPlay4AImpl_Initialize,
+    IDirectPlay4AImpl_Open,
+    IDirectPlay4AImpl_Receive,
+    IDirectPlay4AImpl_Send,
+    IDirectPlay4AImpl_SetGroupData,
+    IDirectPlay4AImpl_SetGroupName,
+    IDirectPlay4AImpl_SetPlayerData,
+    IDirectPlay4AImpl_SetPlayerName,
+    IDirectPlay4AImpl_SetSessionDesc,
+    IDirectPlay4AImpl_AddGroupToGroup,
+    IDirectPlay4AImpl_CreateGroupInGroup,
+    IDirectPlay4AImpl_DeleteGroupFromGroup,
+    IDirectPlay4AImpl_EnumConnections,
+    IDirectPlay4AImpl_EnumGroupsInGroup,
+    IDirectPlay4AImpl_GetGroupConnectionSettings,
+    IDirectPlay4AImpl_InitializeConnection,
+    IDirectPlay4AImpl_SecureOpen,
+    IDirectPlay4AImpl_SendChatMessage,
+    IDirectPlay4AImpl_SetGroupConnectionSettings,
+    IDirectPlay4AImpl_StartSession,
+    IDirectPlay4AImpl_GetGroupFlags,
+    IDirectPlay4AImpl_GetGroupParent,
+    IDirectPlay4AImpl_GetPlayerAccount,
+    IDirectPlay4AImpl_GetPlayerFlags,
+    IDirectPlay4AImpl_GetGroupOwner,
+    IDirectPlay4AImpl_SetGroupOwner,
+    IDirectPlay4AImpl_SendEx,
+    IDirectPlay4AImpl_GetMessageQueue,
+    IDirectPlay4AImpl_CancelMessage,
+    IDirectPlay4AImpl_CancelPriority
 };
-#undef XCAST
 
+HRESULT dplay_create( REFIID riid, void **ppv )
+{
+    IDirectPlayImpl *obj;
+    HRESULT hr;
 
-/* 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
+    TRACE( "(%s, %p)\n", debugstr_guid( riid ), ppv );
+
+    *ppv = NULL;
+    obj = HeapAlloc( GetProcessHeap(), 0, sizeof( *obj ) );
+    if ( !obj )
+        return DPERR_OUTOFMEMORY;
+
+    obj->IDirectPlay_iface.lpVtbl = &dp_vt;
+    obj->IDirectPlay2A_iface.lpVtbl = &dp2A_vt;
+    obj->IDirectPlay2_iface.lpVtbl = &dp2_vt;
+    obj->IDirectPlay3A_iface.lpVtbl = &dp3A_vt;
+    obj->IDirectPlay3_iface.lpVtbl = &dp3_vt;
+    obj->IDirectPlay4A_iface.lpVtbl = &dp4A_vt;
+    obj->IDirectPlay4_iface.lpVtbl = &dp4_vt;
+    obj->numIfaces = 1;
+    obj->ref = 0;
+    obj->ref2A = 0;
+    obj->ref2 = 0;
+    obj->ref3A = 0;
+    obj->ref3 = 0;
+    obj->ref4A = 0;
+    obj->ref4 = 1;
+
+    InitializeCriticalSection( &obj->lock );
+    obj->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlayImpl.lock");
+
+    if ( DP_CreateDirectPlay2( obj ) )
+        hr = IDirectPlayX_QueryInterface( &obj->IDirectPlay4_iface, riid, ppv );
+    else
+        hr = DPERR_NOMEMORY;
+    IDirectPlayX_Release( &obj->IDirectPlay4_iface );
+
+    return hr;
+}
 
-HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
-                            DPID idPlayer,
-                            LPVOID* lplpData )
+
+HRESULT DP_GetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void **lplpData )
 {
   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
 
@@ -5180,9 +5743,7 @@ HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
   return DP_OK;
 }
 
-HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
-                            DPID idPlayer,
-                            LPVOID lpData )
+HRESULT DP_SetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void *lpData )
 {
   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
 
@@ -5437,13 +5998,8 @@ HRESULT WINAPI DirectPlayCreate
     return DPERR_INVALIDPARAMS;
   }
 
-
-  /* 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 )
-  {
+  if ( dplay_create( &IID_IDirectPlay, (void**)lplpDP ) != DP_OK )
     return DPERR_UNAVAILABLE;
-  }
 
   if( IsEqualGUID( &GUID_NULL, lpGUID ) )
   {