- Provide lobby provider COM object header file and stub implementation
- Break out dpl and dp service provider intialization
- Add missing definition of E_PENDING
- Resolve a few fixmes
- Fix includes for dplay.h

diff --git a/dlls/dplayx/Makefile.in b/dlls/dplayx/Makefile.in
index 08fd7d5..cf868e3 100644
--- a/dlls/dplayx/Makefile.in
+++ b/dlls/dplayx/Makefile.in
@@ -16,6 +16,7 @@
 	dplayx_main.c \
 	dplayx_messages.c \
 	dplobby.c \
+	lobbysp.c \
 	name_server.c
 
 @MAKE_DLL_RULES@
diff --git a/dlls/dplayx/dpinit.h b/dlls/dplayx/dpinit.h
index fceecc3..92063d7 100644
--- a/dlls/dplayx/dpinit.h
+++ b/dlls/dplayx/dpinit.h
@@ -9,5 +9,8 @@
 extern HRESULT DPL_CreateInterface( REFIID riid, LPVOID* ppvObj );
 extern HRESULT DPSP_CreateInterface( REFIID riid, LPVOID* ppvObj, 
                                      IDirectPlay2Impl* dp );
+extern HRESULT DPLSP_CreateInterface( REFIID riid, LPVOID* ppvObj,
+                                      IDirectPlay2Impl* dp );
+
 
 #endif
diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c
index 48f6cb4..7548c52 100644
--- a/dlls/dplayx/dplay.c
+++ b/dlls/dplayx/dplay.c
@@ -1,6 +1,6 @@
 /* Direct Play 2,3,4 Implementation
  *
- * Copyright 1998,1999,2000 - Peter Hunnisett
+ * Copyright 1998,1999,2000,2001 - Peter Hunnisett
  *
  * <presently under construction - contact hunnise@nortelnetworks.com>
  *
@@ -169,6 +169,8 @@
 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
     LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
     DWORD dwFlags, LPVOID lpContext );
+static BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
+                                           LPDWORD lpdwBufSize );
 
 
 
@@ -181,6 +183,9 @@
 
 
 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 );
+
 
 
 
@@ -283,6 +288,20 @@
     return FALSE;
   }
 
+  /* Setup lobby provider information */
+  This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
+  This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                         sizeof( *This->dp2->dplspData.lpCB ) );
+  This->dp2->dplspData.lpCB->dwSize = sizeof(  *This->dp2->dplspData.lpCB );
+
+  if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
+                                     (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
+    )
+  {
+    /* FIXME: Memory leak */
+    return FALSE;
+  }
+
   return TRUE;
 }
 
@@ -347,12 +366,17 @@
     (*This->dp2->spData.lpCB->Shutdown)();
   }
 
-  /* Unload the SP */
+  /* Unload the SP (if it exists) */
   if( This->dp2->hServiceProvider != 0 )
   {
     FreeLibrary( This->dp2->hServiceProvider );
   }
 
+  /* Unload the Lobby Provider (if it exists) */
+  if( This->dp2->hDPLobbyProvider != 0 )
+  {
+    FreeLibrary( This->dp2->hDPLobbyProvider );
+  }
 
 #if 0
   DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
@@ -631,6 +655,26 @@
 
   switch( wCommandId )
   {
+    /* Name server needs to handle this request */
+    case DPMSGCMD_ENUMSESSIONSREQUEST:
+    {
+      /* Reply expected */
+      NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
+
+      break;
+    }
+
+    /* Name server needs to handle this request */
+    case DPMSGCMD_ENUMSESSIONSREPLY:
+    {
+      /* No reply expected */
+      NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
+                                        This->dp2->spData.dwSPHeaderSize,
+                                        (LPDPMSG_ENUMSESSIONSREPLY)lpcMessageBody,
+                                        This->dp2->lpNameServerData );
+      break;
+    }
+
     case DPMSGCMD_REQUESTNEWPLAYERID:
     {
       LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = 
@@ -667,11 +711,36 @@
     case DPMSGCMD_NEWPLAYERIDREPLY:
     {
 
+#if 0
+      if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
+        DebugBreak();
+#endif
       DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
  
       break;
     }
     
+#if 1
+    case DPMSGCMD_JUSTENVELOPE:
+    {
+      TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08lx\n", lpcMessageHeader, ((LPDWORD)lpcMessageHeader)[1] );
+      NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
+      DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
+    }
+#endif
+
+    case DPMSGCMD_FORWARDADDPLAYER:
+    {
+#if 0
+      DebugBreak();
+#endif
+#if 1
+    TRACE( "Sending message to self to get my addr\n" );
+    DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
+#endif
+      break;
+    }
+
     case DPMSGCMD_FORWARDADDPLAYERNACK:
     {
       DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
@@ -686,6 +755,8 @@
     }
   }
 
+  /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
+
   return DP_OK;
 }
 
@@ -1475,6 +1546,11 @@
      *        is this used for regular players? If only for server players, move
      *        this call to DP_SecureOpen(...);
      */
+#if 0
+    TRACE( "Sending message to self to get my addr\n" );
+    DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
+#endif
+
     hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
   }
 #else
@@ -2107,6 +2183,47 @@
     return DPERR_GENERIC;
   }
 
+#if 1
+  /* The loading of a lobby provider _seems_ to require a backdoor loading
+   * of the service provider to also associate with this DP object. This is
+   * because the app doesn't seem to have to call EnumConnections and
+   * InitializeConnection for the SP before calling this method. As such
+   * we'll do their dirty work for them with a quick hack so as to always
+   * load the TCP/IP service provider.
+   *
+   * The correct solution would seem to involve creating a dialog box which
+   * contains the possible SPs. These dialog boxes most likely follow SDK
+   * examples.
+   */
+   if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
+   {
+     LPVOID lpConnection;
+     DWORD  dwSize;
+
+     WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
+
+     if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
+     {
+       ERR( "Can't build compound addr\n" );
+       return DPERR_GENERIC;
+     }
+
+     hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
+                                      0, bAnsi );
+     if( FAILED(hr) )
+     {
+       return hr;
+     }
+
+     /* Free up the address buffer */
+     HeapFree( GetProcessHeap(), 0, lpConnection );
+
+     /* The SP is now initialized */
+     This->dp2->bSPInitialized = TRUE;
+   }
+#endif
+
+
   /* Use the service provider default? */
   if( dwTimeout == 0 )
   {
@@ -2158,6 +2275,7 @@
                                                        sizeof( *lpData ) );
         /* FIXME: need to kill the thread on object deletion */
         lpData->lpSpData  = &This->dp2->spData;
+
         CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
         lpData->dwEnumSessionFlags = dwFlags;
         lpData->dwTimeout = dwTimeout;
@@ -2693,7 +2811,7 @@
   {
     /* Rightoo - this computer is the host and the local computer needs to be
        the name server so that others can join this session */
-    NS_SetLocalComputerAsNameServer( lpsd );
+    NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
 
     This->dp2->bHostInterface = TRUE;
 
@@ -3458,6 +3576,45 @@
   return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
 }
 
+static
+BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
+                                    LPDWORD lpdwBufSize )
+{
+  DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
+  HRESULT                  hr;
+
+  dpCompoundAddress.dwDataSize = sizeof( GUID );
+  memcpy( &dpCompoundAddress.guidDataType, &DPAID_ServiceProvider,
+          sizeof( GUID ) ) ;
+  dpCompoundAddress.lpData = lpcSpGuid;
+
+  *lplpAddrBuf = NULL;
+  *lpdwBufSize = 0;
+
+  hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
+                                  lpdwBufSize, TRUE );
+
+  if( hr != DPERR_BUFFERTOOSMALL )
+  {
+    ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
+    return FALSE;
+  }
+
+  /* Now allocate the buffer */
+  *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                            *lpdwBufSize );
+
+  hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
+                                  lpdwBufSize, TRUE );
+  if( FAILED(hr) )
+  {
+    ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
           ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
 {
@@ -3515,9 +3672,8 @@
       char     returnBuffer[51];
       WCHAR    buff[51];
       DPNAME   dpName;
-      HRESULT  hr;
+      BOOL     bBuildPass;
 
-      DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
       LPVOID                   lpAddressBuffer = NULL;
       DWORD                    dwAddressBufferSize = 0;
 
@@ -3551,31 +3707,19 @@
       dpName.u2.lpszLongNameA  = NULL;
 
       /* Create the compound address for the service provider. 
-         NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP,
-               nasty stuff. This may be why the native dll just gets around this little bit by
-               allocating an 80 byte buffer which isn't even filled with a valid compound 
-               address. Oh well. Creating a proper compound address is the way to go anyway... 
-               despite this method taking slightly more heap space and realtime :) */
-      dpCompoundAddress.dwDataSize   = sizeof( GUID );
-      memcpy( &dpCompoundAddress.guidDataType, &DPAID_ServiceProvider, 
-              sizeof( GUID ) ) ;
-      dpCompoundAddress.lpData       = &serviceProviderGUID; 
+         NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
+               nast stuff. This may be why the native dll just gets around this little bit by
+               allocating an 80 byte buffer which isn't even a filled with a valid compound
+               address. Oh well. Creating a proper compound address is the way to go anyways
+                despite this method taking slightly more heap space and realtime :) */
 
-      if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer, 
-                                     &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
+      bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
+                                           &lpAddressBuffer,
+                                           &dwAddressBufferSize );
+      if( !bBuildPass )
       {
-        ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
-        return hr;
-      }
-
-      /* Now allocate the buffer */
-      lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
-
-      if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
-                                     &dwAddressBufferSize, TRUE ) ) != DP_OK )
-      {
-        ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
-        return hr;
+        ERR( "Can't build compound addr\n" );
+        return DPERR_GENERIC;
       }
 
       /* The enumeration will return FALSE if we are not to continue */
@@ -3656,11 +3800,12 @@
       dpName.u2.lpszLongNameA  = NULL;
 
       /* Create the compound address for the service provider. 
-         NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP,
-               nasty stuff. This may be why the native dll just gets around this little bit by
-               allocating an 80 byte buffer which isn't even filled with a valid compound 
-               address. Oh well. Creating a proper compound address is the way to go anyway... 
+         NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
+               nast stuff. This may be why the native dll just gets around this little bit by
+               allocating an 80 byte buffer which isn't even a filled with a valid compound
+               address. Oh well. Creating a proper compound address is the way to go anyways
                despite this method taking slightly more heap space and realtime :) */
+
       dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
       dpCompoundAddress.dwDataSize   = sizeof( GUID );
       dpCompoundAddress.lpData       = &serviceProviderGUID; 
@@ -3895,10 +4040,12 @@
         continue;
       }
 
-      /* Save the name of the SP or LP */
-      len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
-      lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
-      MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
+      if( i == 0 ) /* DP SP */
+      {
+        len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
+        lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
+        MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
+      }
 
       sizeOfReturnBuffer = 255;
 
@@ -3911,7 +4058,10 @@
          continue;
       }
 
-      lpSpData->dwReserved1 = GET_DWORD( returnBuffer );
+      if( i == 0 )
+      {
+        lpSpData->dwReserved1 = GET_DWORD( returnBuffer );
+      }
  
       sizeOfReturnBuffer = 255;
 
@@ -3924,8 +4074,10 @@
          continue;
       }
 
-      lpSpData->dwReserved2 = GET_DWORD( returnBuffer );
-
+      if( i == 0 )
+      {
+        lpSpData->dwReserved2 = GET_DWORD( returnBuffer );
+      }
 
       sizeOfReturnBuffer = 255;
    
@@ -3946,12 +4098,92 @@
   return 0;
 }
 
+static
+HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
+{
+  HRESULT hr;
+  LPDPSP_SPINIT SPInit;
+
+  /* Initialize the service provider by calling SPInit */
+  SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
+ 
+  if( SPInit == NULL )
+  {
+    ERR( "Service provider doesn't provide SPInit interface?\n" );
+    FreeLibrary( hServiceProvider );
+    return DPERR_UNAVAILABLE;
+  } 
+
+  TRACE( "Calling SPInit (DP SP entry point)\n" );
+ 
+  hr = (*SPInit)( &This->dp2->spData );
+
+  if( FAILED(hr) )
+  {
+    ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
+    FreeLibrary( hServiceProvider );
+    return hr;
+  }
+
+  /* FIXME: Need to verify the sanity of the returned callback table
+   *        using IsBadCodePtr */
+  This->dp2->bSPInitialized = TRUE;
+
+  /* This interface is now initialized as a DP object */
+  This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
+
+  /* Store the handle of the module so that we can unload it later */
+  This->dp2->hServiceProvider = hServiceProvider;
+     
+  return hr;
+}
+
+static
+HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
+{
+  HRESULT hr;
+  LPSP_INIT DPLSPInit;
+ 
+  /* Initialize the service provider by calling SPInit */
+  DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
+ 
+  if( DPLSPInit == NULL )
+  {
+    ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
+    FreeLibrary( hLobbyProvider );
+    return DPERR_UNAVAILABLE;
+  } 
+
+  TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
+ 
+  hr = (*DPLSPInit)( &This->dp2->dplspData );
+
+  if( FAILED(hr) )
+  {
+    ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
+    FreeLibrary( hLobbyProvider );
+    return hr;
+  }
+
+  /* FIXME: Need to verify the sanity of the returned callback table
+   *        using IsBadCodePtr */
+
+  This->dp2->bDPLSPInitialized = TRUE;
+   
+  /* This interface is now initialized as a lobby object */
+  This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
+
+  /* Store the handle of the module so that we can unload it later */
+  This->dp2->hDPLobbyProvider = hLobbyProvider;
+     
+  return hr;
+}
+
 static HRESULT WINAPI DP_IF_InitializeConnection
           ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
 {
   HMODULE hServiceProvider;
   HRESULT hr;
-  LPDPSP_SPINIT SPInit;
   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 */
@@ -3963,11 +4195,6 @@
     return DPERR_INVALIDFLAGS;
   }
 
-  if( This->dp2->bConnectionInitialized == TRUE )
-  {
-    return DPERR_ALREADYINITIALIZED;
-  }
-
   /* Find out what the requested SP is and how large this buffer is */
   hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection, 
                         dwAddrSize, &guidSP );
@@ -3978,13 +4205,6 @@
     return DPERR_UNAVAILABLE;
   }
 
-  /* Initialize what we can of the Service Provider required information.
-   * The rest will be done in DP_LoadSP
-   */
-  This->dp2->spData.lpAddress = lpConnection;
-  This->dp2->spData.dwAddressSize = dwAddrSize;
-  This->dp2->spData.lpGuid = &guidSP;
-
   /* Load the service provider */
   hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
 
@@ -3996,43 +4216,27 @@
   
   if( bIsDpSp )
   {
-    /* Initialize the service provider by calling SPInit */
-    SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
+     /* Fill in what we can of the Service Provider required information.
+      * The rest was be done in DP_LoadSP
+      */
+     This->dp2->spData.lpAddress = lpConnection;
+     This->dp2->spData.dwAddressSize = dwAddrSize;
+     This->dp2->spData.lpGuid = &guidSP;
+
+     hr = DP_InitializeDPSP( This, hServiceProvider );
   }
   else
   {
-    /* Initialize the service provider by calling SPInit */
-    SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "DPLSPInit" );    
+     This->dp2->dplspData.lpAddress = lpConnection;
+
+     hr = DP_InitializeDPLSP( This, hServiceProvider );
   }
   
-  if( SPInit == NULL )
-  {
-    ERR( "Service provider doesn't provide %s interface?\n",
-         bIsDpSp ? "SPInit" : "DPLSPInit" );
-    FreeLibrary( hServiceProvider );
-    return DPERR_UNAVAILABLE;
-  }  
-
-  TRACE( "Calling %s (SP entry point)\n", bIsDpSp ? "SPInit" : "DPLSPInit" );
-  
-  /* FIXME: Need to break this out into a separate routine for DP SP and
-   *        DPL SP as they actually use different stuff... 
-   */
-  hr = (*SPInit)( &This->dp2->spData );
-
   if( FAILED(hr) )
   {
-    ERR( "DP/DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
-    FreeLibrary( hServiceProvider );
     return hr;
   }
 
-  /* This interface is now initialized */
-  This->dp2->bConnectionInitialized = TRUE;
-
-  /* Store the handle of the module so that we can unload it later */
-  This->dp2->hServiceProvider = hServiceProvider;
-
   return DP_OK;
 }
 
@@ -4040,6 +4244,13 @@
           ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay3Impl,iface);
+
+  /* This may not be externally invoked once either an SP or LP is initialized */
+  if( This->dp2->connectionInitialized != NO_PROVIDER )
+  {
+    return DPERR_ALREADYINITIALIZED;
+  } 
+
   return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );  
 }
 
@@ -4047,6 +4258,13 @@
           ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay3Impl,iface);
+
+  /* This may not be externally invoked once either an SP or LP is initialized */
+  if( This->dp2->connectionInitialized != NO_PROVIDER )
+  {
+    return DPERR_ALREADYINITIALIZED;
+  }
+
   return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
 }
 
diff --git a/dlls/dplayx/dplay_global.h b/dlls/dplayx/dplay_global.h
index b7daa74..94208c2 100644
--- a/dlls/dplayx/dplay_global.h
+++ b/dlls/dplayx/dplay_global.h
@@ -2,6 +2,7 @@
 #define __WINE_DPLAY_GLOBAL_INCLUDED
 
 #include "dplaysp.h"
+#include "lobbysp.h"
 #include "dplayx_queue.h"
 
 extern HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, 
@@ -126,7 +127,14 @@
 };
 typedef struct DPMSG* LPDPMSG;
 
-/* Contains all dp1 and dp2 data members */
+enum SPSTATE
+{
+  NO_PROVIDER = 0,
+  DP_SERVICE_PROVIDER = 1,
+  DP_LOBBY_PROVIDER = 2
+};
+
+/* Contains all data members. FIXME: Rename me */
 typedef struct tagDirectPlay2Data
 {
   BOOL   bConnectionOpen;
@@ -149,11 +157,19 @@
 
   /* Information about the service provider active on this connection */
   SPINITDATA spData;
+  BOOL       bSPInitialized;
+
+  /* Information about the lobby server that's attached to this DP object */
+  SPDATA_INIT dplspData;
+  BOOL        bDPLSPInitialized;
 
   /* Our service provider */
   HMODULE hServiceProvider;
 
-  BOOL bConnectionInitialized;
+  /* Our DP lobby provider */
+  HMODULE hDPLobbyProvider;
+
+  enum SPSTATE connectionInitialized;
 
   /* Expected messages queue */
   DPQ_HEAD( tagDP_MSG_REPLY_STRUCT_LIST ) replysExpected;
diff --git a/dlls/dplayx/dplaysp.c b/dlls/dplayx/dplaysp.c
index 6fc0443..a661981 100644
--- a/dlls/dplayx/dplaysp.c
+++ b/dlls/dplayx/dplaysp.c
@@ -168,10 +168,8 @@
    * to it (ie we'd be stuck with always having one reference to the dplay
    * object, and hence us, around).
    * NOTE: The dp object does reference count us.
-   */
-  /* IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp ); */
-
-  /* FIXME: This is a kludge to get around a problem where a queryinterface
+   *
+   * FIXME: This is a kludge to get around a problem where a queryinterface
    *        is used to get a new interface and then is closed. We will then
    *        reference garbage. However, with this we will never deallocate
    *        the interface we store. The correct fix is to require all 
@@ -297,6 +295,8 @@
 {
   ICOM_THIS(IDirectPlaySPImpl,iface);
 
+  /* Should be able to call the comctl32 undocumented MRU routines.
+     I suspect that the interface works appropriately */
   FIXME( "(%p)->(%p,%p%p,0x%08lx,0x%08lx): stub\n", 
          This, lpSection, lpKey, lpData, dwDataSize, dwMaxEntries );
 
@@ -350,6 +350,8 @@
 {
   ICOM_THIS(IDirectPlaySPImpl,iface);
 
+  /* Should be able to call the comctl32 undocumented MRU routines.
+     I suspect that the interface works appropriately */
   FIXME( "(%p)->(%p,%p,%p,%p,): stub\n", 
          This, lpSection, lpKey, lpEnumMRUCallback, lpContext );
 
@@ -382,7 +384,6 @@
   LPDP_SPPLAYERDATA lpPlayerData;
   ICOM_THIS(IDirectPlaySPImpl,iface);
 
-/*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
   TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx)\n", 
          This, idPlayer, lplpData, lpdwDataSize, dwFlags );
 
@@ -435,10 +436,10 @@
   HRESULT hr = DPERR_GENERIC;
   WORD wCommandId;
   WORD wVersion;
-
+  DPSP_REPLYDATA data;
+      
   ICOM_THIS(IDirectPlaySPImpl,iface);
 
-/*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
   FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n", 
          This, lpMessageBody, dwMessageBodySize, lpMessageHeader );
 
@@ -451,81 +452,49 @@
   if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG )
   {
     ERR( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic );
+    return DPERR_GENERIC;
   }
 
-  switch( lpMsg->wCommandId )
+#if 0
   {
-    /* Name server needs to handle this request */
-    /* FIXME: This should be done in direct play handler */
-    case DPMSGCMD_ENUMSESSIONSREQUEST:
+    const LPDWORD lpcHeader = (LPDWORD)lpMessageHeader;
+
+    TRACE( "lpMessageHeader = [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx]\n",
+           lpcHeader[0], lpcHeader[1], lpcHeader[2], lpcHeader[3], lpcHeader[4] );
+   }
+#endif
+
+  /* Pass everything else to Direct Play */
+  data.lpMessage     = NULL;
+  data.dwMessageSize = 0;
+
+  /* Pass this message to the dplay interface to handle */
+  hr = DP_HandleMessage( This->sp->dplay, lpMessageBody, dwMessageBodySize,
+                         lpMessageHeader, wCommandId, wVersion, 
+                         &data.lpMessage, &data.dwMessageSize );
+
+  if( FAILED(hr) )
+  {
+    ERR( "Command processing failed %s\n", DPLAYX_HresultToString(hr) );
+  }
+
+  /* Do we want a reply? */
+  if( data.lpMessage != NULL )
+  {
+    data.lpSPMessageHeader = lpMessageHeader;
+    data.idNameServer      = 0;
+    data.lpISP             = iface;
+
+    hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data );
+
+    if( FAILED(hr) )
     {
-      DPSP_REPLYDATA data;
-
-      data.lpSPMessageHeader = lpMessageHeader;
-      data.idNameServer      = 0;
-      data.lpISP             = iface;
- 
-      NS_ReplyToEnumSessionsRequest( lpMessageBody, &data, This->sp->dplay );
-
-      hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data );
-
-      if( FAILED(hr) )
-      {
-        ERR( "Reply failed 0x%08lx\n", hr );
-      }
-
-      break;
-    }
-
-    /* Name server needs to handle this request */
-    /* FIXME: This should be done in direct play handler */
-    case DPMSGCMD_ENUMSESSIONSREPLY:
-    {
-      NS_SetRemoteComputerAsNameServer( lpMessageHeader, 
-                                        This->sp->dplay->dp2->spData.dwSPHeaderSize,
-                                        (LPDPMSG_ENUMSESSIONSREPLY)lpMessageBody,
-                                        This->sp->dplay->dp2->lpNameServerData );
-
-      /* No reply expected */
-      hr = DP_OK;
-
-      break;
-    }
-
-    /* Pass everything else to Direct Play */
-    default:
-    {
-      DPSP_REPLYDATA data;
-      
-      data.lpMessage     = NULL;
-      data.dwMessageSize = 0;
-
-      /* Pass this message to the dplay interface to handle */
-      hr = DP_HandleMessage( This->sp->dplay, lpMessageBody, dwMessageBodySize,
-                             lpMessageHeader, wCommandId, wVersion, 
-                             &data.lpMessage, &data.dwMessageSize );
-
-      /* Do we want a reply? */
-      if( data.lpMessage != NULL )
-      {
-        HRESULT hr;
-
-        data.lpSPMessageHeader = lpMessageHeader;
-        data.idNameServer      = 0;
-        data.lpISP             = iface;
-
-        hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data );
-
-        if( FAILED(hr) )
-        {
-          ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr) );
-        }
-      }
-
-      break;
+      ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr) );
     }
   }
 
+  return hr;
+
 #if 0
   HRESULT hr = DP_OK;
   HANDLE  hReceiveEvent = 0;
@@ -768,8 +737,6 @@
     SetEvent( hReceiveEvent );
   }
 #endif
-
-  return hr;
 }
 
 static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData
@@ -859,7 +826,7 @@
    */
   if( dwFlags != DPSET_REMOTE )
   {
-    FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
+    TRACE( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
   }
 #endif
 
@@ -918,7 +885,7 @@
    */
   if( dwFlags != DPSET_REMOTE )
   {
-    FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
+    TRACE( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
   }
 #endif
 
diff --git a/dlls/dplayx/dplayx_global.c b/dlls/dplayx/dplayx_global.c
index d9b6fa5..e77615c 100644
--- a/dlls/dplayx/dplayx_global.c
+++ b/dlls/dplayx/dplayx_global.c
@@ -1240,10 +1240,8 @@
       return "DPERR_NOPLAYERS";
     case DPERR_NOSESSIONS: 
       return "DPERR_NOSESSIONS";
-/* This one isn't defined yet in WINE sources. I don't know the value
     case DPERR_PENDING: 
       return "DPERR_PENDING";
-*/
     case DPERR_SENDTOOBIG: 
       return "DPERR_SENDTOOBIG";
     case DPERR_TIMEOUT: 
diff --git a/dlls/dplayx/dplayx_messages.c b/dlls/dplayx/dplayx_messages.c
index cf36b6d..1e4342e 100644
--- a/dlls/dplayx/dplayx_messages.c
+++ b/dlls/dplayx/dplayx_messages.c
@@ -1,6 +1,6 @@
 /* DirectPlay & DirectPlayLobby messaging implementation
  *
- * Copyright 2000 - Peter Hunnisett
+ * Copyright 2000,2001 - Peter Hunnisett
  *
  * <presently under construction - contact hunnise@nortelnetworks.com>
  *
@@ -17,6 +17,7 @@
 #include "dplayx_messages.h"
 #include "dplay_global.h"
 #include "dplayx_global.h"
+#include "name_server.h"
 
 DEFAULT_DEBUG_CHANNEL(dplay);
 
@@ -212,7 +213,6 @@
     TRACE( "Asking for player id w/ dwFlags 0x%08lx\n", 
            lpMsgBody->dwFlags );
 
-
     DP_MSG_ExpectReply( This, &data, DPMSG_DEFAULT_WAIT_TIME, DPMSGCMD_NEWPLAYERIDREPLY, 
                         &lpMsg, &dwMsgSize );
   }
@@ -267,7 +267,7 @@
     DWORD  dwDataSize;
     
     /* SP Player remote data needs to be propagated at some point - is this the point? */
-    IDirectPlaySP_GetSPPlayerData( This->dp2->spData.lpISP, dpidServer, (LPVOID*)&lpPData, &dwDataSize, DPSET_REMOTE );
+    IDirectPlaySP_GetSPPlayerData( This->dp2->spData.lpISP, 0, (LPVOID*)&lpPData, &dwDataSize, DPSET_REMOTE );
     
     ERR( "Player Data size is 0x%08lx\n"
          "[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n"
@@ -305,11 +305,22 @@
   lpMsgBody->unknown4[0] =  0x30; 
   lpMsgBody->unknown4[1] =  0xb;
   lpMsgBody->unknown4[2] =  0x0;
-  lpMsgBody->unknown4[3] =  0x1e090002;
+
+  lpMsgBody->unknown4[3] =  NS_GetNsMagic( This->dp2->lpNameServerData ) -
+                            0x02000000;
+  TRACE( "Setting first magic to 0x%08lx\n", lpMsgBody->unknown4[3] );
+
   lpMsgBody->unknown4[4] =  0x0;
   lpMsgBody->unknown4[5] =  0x0;
   lpMsgBody->unknown4[6] =  0x0;
-  lpMsgBody->unknown4[7] =  0x32090002;
+
+#if 0
+  lpMsgBody->unknown4[7] =  NS_GetOtherMagic( This->dp2->lpNameServerData )
+#else
+  lpMsgBody->unknown4[7] =  NS_GetNsMagic( This->dp2->lpNameServerData );
+#endif
+  TRACE( "Setting second magic to 0x%08lx\n", lpMsgBody->unknown4[7] );
+
   lpMsgBody->unknown4[8] =  0x0;
   lpMsgBody->unknown4[9] =  0x0;
   lpMsgBody->unknown4[10] = 0x0;
@@ -331,6 +342,8 @@
     data.bSystemMessage = TRUE; /* Allow reply to be sent */
     data.lpISP          = This->dp2->spData.lpISP;
 
+    TRACE( "Sending forward player request with 0x%08lx\n", dpidServer );
+
     lpMsg = DP_MSG_ExpectReply( This, &data, 
                                 DPMSG_WAIT_60_SECS, 
                                 DPMSGCMD_GETNAMETABLEREPLY,
@@ -372,11 +385,13 @@
 
   if( FAILED(hr) )
   {
-    ERR( "Request for new playerID send failed: %s\n",
-         DPLAYX_HresultToString( hr ) );
+    ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr ) );
     return NULL;
   }
 
+  /* The reply message will trigger the hMsgReceipt event effectively switching
+   * control back to this thread. See DP_MSG_ReplyReceived.
+   */
   dwWaitReturn = WaitForSingleObject( hMsgReceipt, dwWaitTime );
   if( dwWaitReturn != WAIT_OBJECT_0 )
   {
@@ -429,7 +444,43 @@
     ERR( "No receipt event set - only expecting in reply mode\n" );
     DebugBreak();
   }
- 
+}
+
+void DP_MSG_ToSelf( IDirectPlay2AImpl* This, DPID dpidSelf )
+{
+  LPVOID                   lpMsg;
+  LPDPMSG_SENDENVELOPE     lpMsgBody;
+  DWORD                    dwMsgSize;
+
+  dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
+
+  lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
+
+  lpMsgBody = (LPDPMSG_SENDENVELOPE)( (BYTE*)lpMsg +
+                                      This->dp2->spData.dwSPHeaderSize );
+
+  /* Compose dplay message envelope */
+  lpMsgBody->dwMagic    = DPMSGMAGIC_DPLAYMSG;
+  lpMsgBody->wCommandId = DPMSGCMD_JUSTENVELOPE;
+  lpMsgBody->wVersion   = DPMSGVER_DP6;
+
+  /* Send the message to ourselves */
+  {
+    DPSP_SENDDATA data;
+
+    data.dwFlags        = 0;
+    data.idPlayerTo     = dpidSelf; /* Sending to session server */
+    data.idPlayerFrom   = 0; /* Sending from session server */
+    data.lpMessage      = lpMsg;
+    data.dwMessageSize  = dwMsgSize;
+    data.bSystemMessage = TRUE; /* Allow reply to be sent */
+    data.lpISP          = This->dp2->spData.lpISP;
+
+    lpMsg = DP_MSG_ExpectReply( This, &data,
+                                DPMSG_WAIT_5_SECS,
+                                DPMSGCMD_JUSTENVELOPE,
+                                &lpMsg, &dwMsgSize );
+  }
 }
 
 void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId,
diff --git a/dlls/dplayx/dplayx_messages.h b/dlls/dplayx/dplayx_messages.h
index 6c0dd61..191858b 100644
--- a/dlls/dplayx/dplayx_messages.h
+++ b/dlls/dplayx/dplayx_messages.h
@@ -19,6 +19,7 @@
                            LPCVOID lpMsgBody, DWORD dwMsgBodySize );
 void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId,
                            LPCVOID lpMsgBody, DWORD dwMsgBodySize );
+void DP_MSG_ToSelf( IDirectPlay2AImpl* This, DPID dpidSelf );
 
 /* Timings -> 1000 ticks/sec */
 #define DPMSG_WAIT_5_SECS   5000
@@ -47,8 +48,13 @@
 
 #define DPMSGCMD_FORWARDADDPLAYER     19
 
+#define DPMSGCMD_PLAYERCHAT           22
+
 #define DPMSGCMD_FORWARDADDPLAYERNACK 36
 
+#define DPMSGCMD_JUSTENVELOPE         1000
+#define DPMSGCMD_JUSTENVELOPEREPLY    1001
+
 /* This is what DP 6 defines it as. Don't know what it means. All messages
  * defined below are DPMSGVER_DP6.
  */
@@ -163,21 +169,21 @@
   DWORD unknown; /* 0 */
 
   DPID  dpidAppServer; /* Remote application server id */
-  DWORD unknown2[5]; /* ??? */
-#define FORWARDADDPLAYER_UNKNOWN2_INIT { 0x0, 0x1c, 0x6c, 0x50, 0x9 }
+  DWORD unknown2[5]; /* 0x0, 0x1c, 0x6c, 0x50, 0x9 */
 
   DPID  dpidAppServer2; /* Remote application server id again !? */
-  DWORD unknown3[5]; /* ??? */
-#define FORWARDADDPLAYER_UNKNOWN3_INIT { 0x0, 0x0, 0x20, 0x0, 0x0 }
+  DWORD unknown3[5]; /* 0x0, 0x0, 0x20, 0x0, 0x0 */
 
   DPID  dpidAppServer3; /* Remote application server id again !? */
 
   DWORD unknown4[12]; /* ??? - Is this a clump of 5 and then 8? */
-                      /* NOTE: 1 byte infront of the two 0x??090002 entries changes! */
+                      /* NOTE: 1 byte infront of the two 0x??090002 entries changes!
+                      *       Is it a timestamp of some sort? 1st always smaller than
+                      *       other...
+                      */
 #define FORWARDADDPLAYER_UNKNOWN4_INIT { 0x30, 0xb, 0x0, 0x1e090002, 0x0, 0x0, 0x0, 0x32090002, 0x0, 0x0, 0x0, 0x0 }
 
-  BYTE unknown5[2]; /* 2 bytes at the end. This may be a part of something! */
-#define FORWARDADDPLAYER_UNKNOWN5_INIT { 0x0 }
+  BYTE unknown5[2]; /* 2 bytes at the end. This may be a part of something! ( 0x0, 0x0) */
 
 } DPMSG_FORWARDADDPLAYER, *LPDPMSG_FORWARDADDPLAYER;
 typedef const DPMSG_FORWARDADDPLAYER* LPCDPMSG_FORWARDADDPLAYER;
diff --git a/dlls/dplayx/lobbysp.c b/dlls/dplayx/lobbysp.c
new file mode 100644
index 0000000..3a18830
--- /dev/null
+++ b/dlls/dplayx/lobbysp.c
@@ -0,0 +1,454 @@
+/* This contains the implementation of the Lobby Service
+ * Providers interface required to communicate with Direct Play
+ *
+ * Copyright 2001 Peter Hunnisett <hunnise@nortelnetworks.com>
+ */
+
+#include "winerror.h"
+#include "debugtools.h"
+
+#include "lobbysp.h"
+#include "dplay_global.h"
+#include "dpinit.h"
+
+DEFAULT_DEBUG_CHANNEL(dplay);
+
+/* Prototypes */
+static BOOL DPLSP_CreateIUnknown( LPVOID lpSP );
+static BOOL DPLSP_DestroyIUnknown( LPVOID lpSP );
+static BOOL DPLSP_CreateDPLobbySP( LPVOID lpSP, IDirectPlay2Impl* dp );
+static BOOL DPLSP_DestroyDPLobbySP( LPVOID lpSP );
+
+
+/* Predefine the interface */
+typedef struct IDPLobbySPImpl IDPLobbySPImpl;
+
+typedef struct tagDPLobbySPIUnknownData
+{
+  ULONG             ulObjRef;
+  CRITICAL_SECTION  DPLSP_lock;
+} DPLobbySPIUnknownData;
+
+typedef struct tagDPLobbySPData
+{
+  IDirectPlay2Impl* dplay;
+} DPLobbySPData;
+
+#define DPLSP_IMPL_FIELDS \
+   ULONG ulInterfaceRef; \
+   DPLobbySPIUnknownData* unk; \
+   DPLobbySPData* sp;
+
+struct IDPLobbySPImpl
+{
+  ICOM_VFIELD(IDPLobbySP);
+  DPLSP_IMPL_FIELDS
+};
+
+/* Forward declaration of virtual tables */
+static ICOM_VTABLE(IDPLobbySP) dpLobbySPVT;
+
+extern
+HRESULT DPLSP_CreateInterface( REFIID riid, LPVOID* ppvObj, IDirectPlay2Impl* dp )
+{
+  TRACE( " for %s\n", debugstr_guid( riid ) );
+
+  *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                       sizeof( IDPLobbySPImpl ) );
+
+  if( *ppvObj == NULL )
+  {
+    return DPERR_OUTOFMEMORY;
+  }
+
+  if( IsEqualGUID( &IID_IDPLobbySP, riid ) )
+  {
+    ICOM_THIS(IDPLobbySPImpl,*ppvObj);
+    ICOM_VTBL(This) = &dpLobbySPVT;
+  }
+  else
+  {
+    /* Unsupported interface */
+    HeapFree( GetProcessHeap(), 0, *ppvObj );
+    *ppvObj = NULL;
+
+    return E_NOINTERFACE;
+  }
+
+  /* Initialize it */
+  if( DPLSP_CreateIUnknown( *ppvObj ) &&
+      DPLSP_CreateDPLobbySP( *ppvObj, dp )
+    )
+  {
+    IDPLobbySP_AddRef( (LPDPLOBBYSP)*ppvObj );
+    return S_OK;
+  }
+
+  /* Initialize failed, destroy it */
+  DPLSP_DestroyDPLobbySP( *ppvObj );
+  DPLSP_DestroyIUnknown( *ppvObj );
+
+  HeapFree( GetProcessHeap(), 0, *ppvObj );
+  *ppvObj = NULL;
+
+  return DPERR_NOMEMORY;
+}
+
+static BOOL DPLSP_CreateIUnknown( LPVOID lpSP )
+{
+  ICOM_THIS(IDPLobbySPImpl,lpSP);
+
+  This->unk = (DPLobbySPIUnknownData*)HeapAlloc( GetProcessHeap(),
+                                                    HEAP_ZERO_MEMORY,
+                                                    sizeof( *(This->unk) ) );
+
+  if ( This->unk == NULL )
+  {
+    return FALSE;
+  }
+
+  InitializeCriticalSection( &This->unk->DPLSP_lock );
+
+  return TRUE;
+}
+
+static BOOL DPLSP_DestroyIUnknown( LPVOID lpSP )
+{
+  ICOM_THIS(IDPLobbySPImpl,lpSP);
+
+  DeleteCriticalSection( &This->unk->DPLSP_lock );
+  HeapFree( GetProcessHeap(), 0, This->unk );
+
+  return TRUE;
+}
+
+static BOOL DPLSP_CreateDPLobbySP( LPVOID lpSP, IDirectPlay2Impl* dp )
+{
+  ICOM_THIS(IDPLobbySPImpl,lpSP);
+
+  This->sp = (DPLobbySPData*)HeapAlloc( GetProcessHeap(),
+                                        HEAP_ZERO_MEMORY,
+                                        sizeof( *(This->sp) ) );
+
+  if ( This->sp == NULL )
+  {
+    return FALSE;
+  }
+
+  This->sp->dplay = dp;
+
+  /* Normally we should be keeping a reference, but since only the dplay
+   * interface that created us can destroy us, we do not keep a reference
+   * to it (ie we'd be stuck with always having one reference to the dplay
+   * object, and hence us, around).
+   * NOTE: The dp object does reference count us.
+   *
+   * FIXME: This is a kludge to get around a problem where a queryinterface
+   *        is used to get a new interface and then is closed. We will then
+   *        reference garbage. However, with this we will never deallocate
+   *        the interface we store. The correct fix is to require all
+   *        DP internal interfaces to use the This->dp2 interface which
+   *        should be changed to This->dp
+   */
+  IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp );
+
+
+  return TRUE;
+}
+
+static BOOL DPLSP_DestroyDPLobbySP( LPVOID lpSP )
+{
+  ICOM_THIS(IDPLobbySPImpl,lpSP);
+
+  HeapFree( GetProcessHeap(), 0, This->sp );
+
+  return TRUE;
+}
+
+static
+HRESULT WINAPI DPLSP_QueryInterface
+( LPDPLOBBYSP iface, 
+  REFIID riid,
+  LPVOID* ppvObj 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
+
+  *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                       sizeof( *This ) );
+
+  if( *ppvObj == NULL )
+  {
+    return DPERR_OUTOFMEMORY;
+  }
+
+  CopyMemory( *ppvObj, This, sizeof( *This )  );
+  (*(IDPLobbySPImpl**)ppvObj)->ulInterfaceRef = 0;
+
+  if( IsEqualGUID( &IID_IDPLobbySP, riid ) )
+  {
+    ICOM_THIS(IDPLobbySPImpl,*ppvObj);
+    ICOM_VTBL(This) = &dpLobbySPVT;
+  }
+  else
+  {
+    /* Unsupported interface */
+    HeapFree( GetProcessHeap(), 0, *ppvObj );
+    *ppvObj = NULL;
+
+    return E_NOINTERFACE;
+  }
+
+  IDPLobbySP_AddRef( (LPDPLOBBYSP)*ppvObj );
+
+  return S_OK;
+}
+
+static 
+ULONG WINAPI DPLSP_AddRef
+( LPDPLOBBYSP iface )
+{
+  ULONG ulInterfaceRefCount, ulObjRefCount;
+  ICOM_THIS(IDPLobbySPImpl,iface);
+
+  ulObjRefCount       = InterlockedIncrement( &This->unk->ulObjRef );
+  ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
+
+  TRACE( "ref count incremented to %lu:%lu for %p\n",
+         ulInterfaceRefCount, ulObjRefCount, This );
+
+  return ulObjRefCount;
+}
+
+static
+ULONG WINAPI DPLSP_Release
+( LPDPLOBBYSP iface )
+{
+  ULONG ulInterfaceRefCount, ulObjRefCount;
+  ICOM_THIS(IDPLobbySPImpl,iface);
+
+  ulObjRefCount       = InterlockedDecrement( &This->unk->ulObjRef );
+  ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
+
+  TRACE( "ref count decremented to %lu:%lu for %p\n",
+         ulInterfaceRefCount, ulObjRefCount, This );
+
+  /* Deallocate if this is the last reference to the object */
+  if( ulObjRefCount == 0 )
+  {
+     DPLSP_DestroyDPLobbySP( This );
+     DPLSP_DestroyIUnknown( This );
+  }
+
+  if( ulInterfaceRefCount == 0 )
+  {
+    HeapFree( GetProcessHeap(), 0, This );
+  }
+
+  return ulInterfaceRefCount;
+}
+
+static 
+HRESULT WINAPI IDPLobbySPImpl_AddGroupToGroup
+( LPDPLOBBYSP iface, 
+  LPSPDATA_ADDREMOTEGROUPTOGROUP argtg 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, argtg );
+  return DP_OK;
+}
+
+static 
+HRESULT WINAPI IDPLobbySPImpl_AddPlayerToGroup
+( LPDPLOBBYSP iface, 
+  LPSPDATA_ADDREMOTEPLAYERTOGROUP arptg 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, arptg );
+  return DP_OK;
+}
+
+static 
+HRESULT WINAPI IDPLobbySPImpl_CreateGroup
+( LPDPLOBBYSP iface, 
+  LPSPDATA_CREATEREMOTEGROUP crg 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, crg );
+  return DP_OK;
+}
+
+static 
+HRESULT WINAPI IDPLobbySPImpl_CreateGroupInGroup
+( LPDPLOBBYSP iface, 
+  LPSPDATA_CREATEREMOTEGROUPINGROUP crgig 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, crgig );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_DeleteGroupFromGroup
+( LPDPLOBBYSP iface, 
+  LPSPDATA_DELETEREMOTEGROUPFROMGROUP drgfg 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, drgfg );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_DeletePlayerFromGroup
+( LPDPLOBBYSP iface, 
+  LPSPDATA_DELETEREMOTEPLAYERFROMGROUP drpfg 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, drpfg );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_DestroyGroup
+( LPDPLOBBYSP iface, 
+  LPSPDATA_DESTROYREMOTEGROUP drg 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, drg );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_EnumSessionsResponse
+( LPDPLOBBYSP iface, 
+  LPSPDATA_ENUMSESSIONSRESPONSE er 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, er );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_GetSPDataPointer
+( LPDPLOBBYSP iface, 
+  LPVOID* lplpData 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, lplpData );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_HandleMessage
+( LPDPLOBBYSP iface, 
+  LPSPDATA_HANDLEMESSAGE hm 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, hm );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_SendChatMessage
+( LPDPLOBBYSP iface, 
+  LPSPDATA_CHATMESSAGE cm 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, cm );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_SetGroupName
+( LPDPLOBBYSP iface, 
+  LPSPDATA_SETREMOTEGROUPNAME srgn 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, srgn );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_SetPlayerName
+( LPDPLOBBYSP iface, 
+  LPSPDATA_SETREMOTEPLAYERNAME srpn 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, srpn );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_SetSessionDesc
+( LPDPLOBBYSP iface, 
+  LPSPDATA_SETSESSIONDESC ssd 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, ssd );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_SetSPDataPointer
+( LPDPLOBBYSP iface, 
+  LPVOID lpData 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, lpData );
+  return DP_OK;
+}
+
+static
+HRESULT WINAPI IDPLobbySPImpl_StartSession
+( LPDPLOBBYSP iface, 
+  LPSPDATA_STARTSESSIONCOMMAND ssc 
+)
+{
+  ICOM_THIS(IDPLobbySPImpl,iface);
+  FIXME( "(%p)->(%p):stub\n", This, ssc );
+  return DP_OK;
+}
+
+
+static struct ICOM_VTABLE(IDPLobbySP) dpLobbySPVT =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+
+  DPLSP_QueryInterface,
+  DPLSP_AddRef,
+  DPLSP_Release,
+
+  IDPLobbySPImpl_AddGroupToGroup,
+  IDPLobbySPImpl_AddPlayerToGroup,
+  IDPLobbySPImpl_CreateGroup,
+  IDPLobbySPImpl_CreateGroupInGroup,
+  IDPLobbySPImpl_DeleteGroupFromGroup,
+  IDPLobbySPImpl_DeletePlayerFromGroup,
+  IDPLobbySPImpl_DestroyGroup,
+  IDPLobbySPImpl_EnumSessionsResponse,
+  IDPLobbySPImpl_GetSPDataPointer,
+  IDPLobbySPImpl_HandleMessage,
+  IDPLobbySPImpl_SendChatMessage,
+  IDPLobbySPImpl_SetGroupName, 
+  IDPLobbySPImpl_SetPlayerName, 
+  IDPLobbySPImpl_SetSessionDesc,
+  IDPLobbySPImpl_SetSPDataPointer,
+  IDPLobbySPImpl_StartSession
+
+};
diff --git a/dlls/dplayx/lobbysp.h b/dlls/dplayx/lobbysp.h
new file mode 100644
index 0000000..ff3bc6d
--- /dev/null
+++ b/dlls/dplayx/lobbysp.h
@@ -0,0 +1,494 @@
+#ifndef __WINE_LOBBY_SP_H
+#define __WINE_LOBBY_SP_H
+
+#include "dplobby.h"
+
+/* GUID for IDPLobbySP {5A4E5A20-2CED-11d0-A889-00A0C905433C} */
+DEFINE_GUID(IID_IDPLobbySP, 0x5a4e5a20, 0x2ced, 0x11d0, 0xa8, 0x89, 0x0, 0xa0, 0xc9, 0x5, 0x43, 0x3c);
+typedef struct IDPLobbySP IDPLobbySP, *LPDPLOBBYSP;
+
+/* For SP. Top 16 bits is dplay, bottom 16 is SP */
+#define DPLSP_MAJORVERSION               0x00050000
+
+typedef struct SPDATA_ADDGROUPTOGROUP
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwParentID;
+  DWORD       dwGroupID;
+} SPDATA_ADDGROUPTOGROUP, *LPSPDATA_ADDGROUPTOGROUP;
+
+typedef struct SPDATA_ADDPLAYERTOGROUP
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+  DWORD       dwPlayerID;
+} SPDATA_ADDPLAYERTOGROUP, *LPSPDATA_ADDPLAYERTOGROUP;
+
+typedef struct SPDATA_ADDREMOTEGROUPTOGROUP
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD	      dwAnchorID;
+  DWORD       dwGroupID;
+  DWORD	      dwParentID;
+  LPDPNAME    lpName;
+  DWORD       dwGroupFlags;
+} SPDATA_ADDREMOTEGROUPTOGROUP, *LPSPDATA_ADDREMOTEGROUPTOGROUP;
+
+typedef struct SPDATA_ADDREMOTEPLAYERTOGROUP
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD	      dwGroupID;
+  DWORD	      dwPlayerID;
+  DWORD	      dwPlayerFlags;
+  LPDPNAME    lpName;
+} SPDATA_ADDREMOTEPLAYERTOGROUP, *LPSPDATA_ADDREMOTEPLAYERTOGROUP;
+
+typedef struct SPDATA_BUILDPARENTALHEIRARCHY
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+  DWORD       dwMessage;
+  DWORD       dwParentID;
+} SPDATA_BUILDPARENTALHEIRARCHY, *LPSPDATA_BUILDPARENTALHEIRARCHY;
+
+typedef struct SPDATA_CLOSE
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+} SPDATA_CLOSE, *LPSPDATA_CLOSE;
+
+typedef struct SPDATA_CREATEGROUP
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+  LPDPNAME    lpName;
+  LPVOID      lpData;
+  DWORD       dwDataSize;
+  DWORD       dwFlags;
+} SPDATA_CREATEGROUP, *LPSPDATA_CREATEGROUP;
+
+typedef struct SPDATA_CREATEGROUPINGROUP
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwParentID;
+  DWORD       dwGroupID;
+  LPDPNAME    lpName;
+  LPVOID      lpData;
+  DWORD       dwDataSize;
+  DWORD       dwFlags;
+} SPDATA_CREATEGROUPINGROUP, *LPSPDATA_CREATEGROUPINGROUP;
+
+typedef struct SPDATA_CREATEREMOTEGROUP
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+  LPDPNAME    lpName;
+  LPVOID      lpData;
+  DWORD       dwDataSize;
+  DWORD       dwFlags;
+} SPDATA_CREATEREMOTEGROUP, *LPSPDATA_CREATEREMOTEGROUP;
+
+typedef struct SPDATA_CREATEREMOTEGROUPINGROUP
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwParentID;
+  DWORD       dwGroupID;
+  LPDPNAME    lpName;
+  DWORD       dwFlags;
+} SPDATA_CREATEREMOTEGROUPINGROUP, *LPSPDATA_CREATEREMOTEGROUPINGROUP;
+
+typedef struct SPDATA_CREATEPLAYER
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwPlayerID;
+  LPDPNAME    lpName;
+  LPVOID      lpData;
+  DWORD       dwDataSize;
+  DWORD       dwFlags;
+} SPDATA_CREATEPLAYER, *LPSPDATA_CREATEPLAYER;
+
+typedef struct SPDATA_DELETEGROUPFROMGROUP
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwParentID;
+  DWORD       dwGroupID;
+} SPDATA_DELETEGROUPFROMGROUP, *LPSPDATA_DELETEGROUPFROMGROUP;
+
+typedef struct SPDATA_DELETEPLAYERFROMGROUP
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+  DWORD       dwPlayerID;
+} SPDATA_DELETEPLAYERFROMGROUP, *LPSPDATA_DELETEPLAYERFROMGROUP;
+
+typedef struct SPDATA_DELETEREMOTEGROUPFROMGROUP
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwParentID;
+  DWORD       dwGroupID;
+} SPDATA_DELETEREMOTEGROUPFROMGROUP, *LPSPDATA_DELETEREMOTEGROUPFROMGROUP;
+
+typedef struct SPDATA_DELETEREMOTEPLAYERFROMGROUP
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+  DWORD       dwPlayerID;
+} SPDATA_DELETEREMOTEPLAYERFROMGROUP, *LPSPDATA_DELETEREMOTEPLAYERFROMGROUP;
+
+typedef struct SPDATA_DESTROYGROUP
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD	      dwGroupID;
+} SPDATA_DESTROYGROUP, *LPSPDATA_DESTROYGROUP;
+
+typedef struct SPDATA_DESTROYREMOTEGROUP
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+} SPDATA_DESTROYREMOTEGROUP, *LPSPDATA_DESTROYREMOTEGROUP;
+
+typedef struct SPDATA_DESTROYPLAYER
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwPlayerID;
+} SPDATA_DESTROYPLAYER, *LPSPDATA_DESTROYPLAYER;
+
+typedef struct SPDATA_ENUMSESSIONS
+{
+  DWORD            dwSize;
+  LPDPLOBBYSP      lpISP;
+  LPDPSESSIONDESC2 lpsd;
+  DWORD            dwTimeout;
+  DWORD            dwFlags;
+} SPDATA_ENUMSESSIONS, *LPSPDATA_ENUMSESSIONS;
+
+typedef struct SPDATA_ENUMSESSIONSRESPONSE
+{
+  DWORD            dwSize;
+  LPDPSESSIONDESC2 lpsd;
+} SPDATA_ENUMSESSIONSRESPONSE, *LPSPDATA_ENUMSESSIONSRESPONSE;
+
+typedef struct SPDATA_GETCAPS
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwFlags;
+  LPDPCAPS    lpcaps;
+} SPDATA_GETCAPS, *LPSPDATA_GETCAPS;
+
+typedef struct SPDATA_GETGROUPCONNECTIONSETTINGS
+{
+  DWORD       dwSize;
+  DWORD       dwFlags;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+  LPDWORD     lpdwBufferSize;
+  LPVOID      lpBuffer;
+} SPDATA_GETGROUPCONNECTIONSETTINGS, *LPSPDATA_GETGROUPCONNECTIONSETTINGS;
+
+typedef struct SPDATA_GETGROUPDATA
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+  LPDWORD     lpdwDataSize;
+  LPVOID      lpData;
+} SPDATA_GETGROUPDATA, *LPSPDATA_GETGROUPDATA;
+
+typedef struct SPDATA_GETPLAYERCAPS
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwFlags;
+  DWORD       dwPlayerID;
+  LPDPCAPS    lpcaps;
+} SPDATA_GETPLAYERCAPS, *LPSPDATA_GETPLAYERCAPS;
+
+typedef struct SPDATA_GETPLAYERDATA
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwPlayerID;
+  LPDWORD     lpdwDataSize;
+  LPVOID      lpData;
+} SPDATA_GETPLAYERDATA, *LPSPDATA_GETPLAYERDATA;
+
+typedef struct SPDATA_HANDLEMESSAGE
+{
+  DWORD	 dwSize;
+  DWORD	 dwFromID;
+  DWORD	 dwToID;
+  LPVOID lpBuffer;
+  DWORD	 dwBufSize;
+} SPDATA_HANDLEMESSAGE, *LPSPDATA_HANDLEMESSAGE;
+
+typedef struct SPDATA_OPEN
+{
+  DWORD	           dwSize;
+  LPDPLOBBYSP      lpISP;
+  LPDPSESSIONDESC2 lpsd;
+  DWORD            dwFlags;
+  LPCDPCREDENTIALS lpCredentials;
+} SPDATA_OPEN, *LPSPDATA_OPEN;
+
+typedef struct SPDATA_SEND
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwFromID;
+  DWORD       dwToID;
+  DWORD       dwFlags;
+  LPVOID      lpBuffer;
+  DWORD       dwBufSize;
+} SPDATA_SEND, *LPSPDATA_SEND;
+
+typedef struct SPDATA_CHATMESSAGE
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwFromID;
+  DWORD       dwToID;
+  DWORD       dwFlags;
+  LPDPCHAT    lpChat;
+} SPDATA_CHATMESSAGE, *LPSPDATA_CHATMESSAGE;
+
+typedef struct SPDATA_SETGROUPCONNECTIONSETTINGS
+{
+  DWORD           dwSize;
+  DWORD           dwFlags;
+  LPDPLOBBYSP     lpISP;
+  DWORD           dwGroupID;
+  LPDPLCONNECTION lpConn;
+} SPDATA_SETGROUPCONNECTIONSETTINGS, *LPSPDATA_SETGROUPCONNECTIONSETTINGS;
+
+typedef struct SPDATA_SETGROUPDATA
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+  LPVOID      lpData;
+  DWORD       dwDataSize;
+  DWORD       dwFlags;
+} SPDATA_SETGROUPDATA, *LPSPDATA_SETGROUPDATA;
+
+typedef struct SPDATA_SETGROUPNAME
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+  LPDPNAME    lpName;
+  DWORD       dwFlags;
+} SPDATA_SETGROUPNAME, *LPSPDATA_SETGROUPNAME;
+
+typedef struct SPDATA_SETREMOTEGROUPNAME
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwGroupID;
+  LPDPNAME    lpName;
+  DWORD       dwFlags;
+} SPDATA_SETREMOTEGROUPNAME, *LPSPDATA_SETREMOTEGROUPNAME;
+
+typedef struct SPDATA_SETPLAYERDATA
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwPlayerID;
+  LPVOID      lpData;
+  DWORD       dwDataSize;
+  DWORD       dwFlags;
+} SPDATA_SETPLAYERDATA, *LPSPDATA_SETPLAYERDATA;
+
+typedef struct SPDATA_SETPLAYERNAME
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwPlayerID;
+  LPDPNAME    lpName;
+  DWORD	      dwFlags;
+} SPDATA_SETPLAYERNAME, *LPSPDATA_SETPLAYERNAME;
+
+typedef struct SPDATA_SETREMOTEPLAYERNAME
+{
+  DWORD	      dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwPlayerID;
+  LPDPNAME    lpName;
+  DWORD       dwFlags;
+} SPDATA_SETREMOTEPLAYERNAME, *LPSPDATA_SETREMOTEPLAYERNAME;
+
+typedef struct SPDATA_SETSESSIONDESC
+{
+  DWORD            dwSize;
+  LPDPSESSIONDESC2 lpsd;
+} SPDATA_SETSESSIONDESC, *LPSPDATA_SETSESSIONDESC;
+
+typedef struct SPDATA_SHUTDOWN
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+} SPDATA_SHUTDOWN, *LPSPDATA_SHUTDOWN;
+
+typedef struct SPDATA_STARTSESSION
+{
+  DWORD       dwSize;
+  LPDPLOBBYSP lpISP;
+  DWORD       dwFlags;
+  DWORD       dwGroupID;
+} SPDATA_STARTSESSION, *LPSPDATA_STARTSESSION;
+
+typedef struct SPDATA_STARTSESSIONCOMMAND
+{
+  DWORD           dwFlags;
+  DWORD           dwGroupID;
+  DWORD           dwHostID;
+  LPDPLCONNECTION lpConn;
+} SPDATA_STARTSESSIONCOMMAND, *LPSPDATA_STARTSESSIONCOMMAND;
+
+/* Prototypes for callbacks returned by DPLSPInit */
+typedef HRESULT (WINAPI *LPSP_ADDGROUPTOGROUP)(LPSPDATA_ADDGROUPTOGROUP);
+typedef HRESULT	(WINAPI *LPSP_ADDPLAYERTOGROUP)(LPSPDATA_ADDPLAYERTOGROUP);
+typedef HRESULT	(WINAPI *LPSP_BUILDPARENTALHEIRARCHY)(LPSPDATA_BUILDPARENTALHEIRARCHY);
+typedef HRESULT	(WINAPI *LPSP_CLOSE)(LPSPDATA_CLOSE);
+typedef HRESULT	(WINAPI *LPSP_CREATEGROUP)(LPSPDATA_CREATEGROUP);
+typedef HRESULT (WINAPI *LPSP_CREATEGROUPINGROUP)(LPSPDATA_CREATEGROUPINGROUP);
+typedef HRESULT	(WINAPI *LPSP_CREATEPLAYER)(LPSPDATA_CREATEPLAYER);
+typedef HRESULT (WINAPI *LPSP_DELETEGROUPFROMGROUP)(LPSPDATA_DELETEGROUPFROMGROUP);
+typedef HRESULT	(WINAPI *LPSP_DELETEPLAYERFROMGROUP)(LPSPDATA_DELETEPLAYERFROMGROUP);
+typedef HRESULT	(WINAPI *LPSP_DESTROYGROUP)(LPSPDATA_DESTROYGROUP);
+typedef HRESULT	(WINAPI *LPSP_DESTROYPLAYER)(LPSPDATA_DESTROYPLAYER);
+typedef HRESULT	(WINAPI *LPSP_ENUMSESSIONS)(LPSPDATA_ENUMSESSIONS);
+typedef HRESULT (WINAPI *LPSP_GETCAPS)(LPSPDATA_GETCAPS);
+typedef HRESULT (WINAPI *LPSP_GETGROUPCONNECTIONSETTINGS)(LPSPDATA_GETGROUPCONNECTIONSETTINGS);
+typedef HRESULT	(WINAPI *LPSP_GETGROUPDATA)(LPSPDATA_GETGROUPDATA);
+typedef HRESULT (WINAPI *LPSP_GETPLAYERCAPS)(LPSPDATA_GETPLAYERCAPS);
+typedef HRESULT	(WINAPI *LPSP_GETPLAYERDATA)(LPSPDATA_GETPLAYERDATA);
+typedef HRESULT	(WINAPI *LPSP_HANDLEMESSAGE)(LPSPDATA_HANDLEMESSAGE);
+typedef HRESULT	(WINAPI *LPSP_OPEN)(LPSPDATA_OPEN);
+typedef HRESULT	(WINAPI *LPSP_SEND)(LPSPDATA_SEND);
+typedef HRESULT	(WINAPI *LPSP_SENDCHATMESSAGE)(LPSPDATA_CHATMESSAGE);
+typedef HRESULT (WINAPI *LPSP_SETGROUPCONNECTIONSETTINGS)(LPSPDATA_SETGROUPCONNECTIONSETTINGS);
+typedef HRESULT	(WINAPI *LPSP_SETGROUPDATA)(LPSPDATA_SETGROUPDATA);
+typedef HRESULT	(WINAPI *LPSP_SETGROUPNAME)(LPSPDATA_SETGROUPNAME);
+typedef HRESULT	(WINAPI *LPSP_SETPLAYERDATA)(LPSPDATA_SETPLAYERDATA);
+typedef HRESULT	(WINAPI *LPSP_SETPLAYERNAME)(LPSPDATA_SETPLAYERNAME);
+typedef HRESULT	(WINAPI *LPSP_SHUTDOWN)(LPSPDATA_SHUTDOWN);
+typedef HRESULT (WINAPI *LPSP_STARTSESSION)(LPSPDATA_STARTSESSION);
+
+/* Callback table for dplay to call into service provider */
+typedef struct SP_CALLBACKS
+{
+  DWORD                            dwSize;
+  DWORD                            dwFlags;
+  LPSP_ADDGROUPTOGROUP             AddGroupToGroup;
+  LPSP_ADDPLAYERTOGROUP            AddPlayerToGroup;
+  LPSP_BUILDPARENTALHEIRARCHY      BuildParentalHeirarchy;
+  LPSP_CLOSE                       Close;
+  LPSP_CREATEGROUP                 CreateGroup;
+  LPSP_CREATEGROUPINGROUP          CreateGroupInGroup;
+  LPSP_CREATEPLAYER                CreatePlayer;
+  LPSP_DELETEGROUPFROMGROUP        DeleteGroupFromGroup;
+  LPSP_DELETEPLAYERFROMGROUP       DeletePlayerFromGroup;
+  LPSP_DESTROYGROUP                DestroyGroup;
+  LPSP_DESTROYPLAYER               DestroyPlayer;
+  LPSP_ENUMSESSIONS                EnumSessions;
+  LPSP_GETCAPS                     GetCaps;
+  LPSP_GETGROUPCONNECTIONSETTINGS  GetGroupConnectionSettings;
+  LPSP_GETGROUPDATA                GetGroupData;
+  LPSP_GETPLAYERCAPS               GetPlayerCaps;
+  LPSP_GETPLAYERDATA               GetPlayerData;
+  LPSP_OPEN                        Open;
+  LPSP_SEND                        Send;
+  LPSP_SENDCHATMESSAGE	           SendChatMessage;
+  LPSP_SETGROUPCONNECTIONSETTINGS  SetGroupConnectionSettings;
+  LPSP_SETGROUPDATA                SetGroupData;
+  LPSP_SETGROUPNAME                SetGroupName;
+  LPSP_SETPLAYERDATA               SetPlayerData;
+  LPSP_SETPLAYERNAME               SetPlayerName;
+  LPSP_SHUTDOWN                    Shutdown;
+  LPSP_STARTSESSION                StartSession;
+} SP_CALLBACKS, *LPSP_CALLBACKS;             
+
+typedef struct SPDATA_INIT 
+{
+  LPSP_CALLBACKS lpCB;
+  DWORD          dwSPVersion;
+  LPDPLOBBYSP    lpISP;
+  LPDPADDRESS    lpAddress;
+} SPDATA_INIT, *LPSPDATA_INIT;
+
+typedef HRESULT (WINAPI *LPSP_INIT)(LPSPDATA_INIT);
+HRESULT WINAPI DPLSPInit(LPSPDATA_INIT);
+
+/* Define the COM interface */
+#define ICOM_INTERFACE IDPLobbySP
+#define IDPLobbySP_METHODS \
+  ICOM_METHOD1(HRESULT, AddGroupToGroup,       LPSPDATA_ADDREMOTEGROUPTOGROUP, argtg ) \
+  ICOM_METHOD1(HRESULT, AddPlayerToGroup,      LPSPDATA_ADDREMOTEPLAYERTOGROUP, arptg ) \
+  ICOM_METHOD1(HRESULT, CreateGroup,           LPSPDATA_CREATEREMOTEGROUP, crg ) \
+  ICOM_METHOD1(HRESULT, CreateGroupInGroup,    LPSPDATA_CREATEREMOTEGROUPINGROUP, crgig ) \
+  ICOM_METHOD1(HRESULT, DeleteGroupFromGroup,  LPSPDATA_DELETEREMOTEGROUPFROMGROUP, drgfg ) \
+  ICOM_METHOD1(HRESULT, DeletePlayerFromGroup, LPSPDATA_DELETEREMOTEPLAYERFROMGROUP, drpfg ) \
+  ICOM_METHOD1(HRESULT, DestroyGroup,          LPSPDATA_DESTROYREMOTEGROUP, drg ) \
+  ICOM_METHOD1(HRESULT, EnumSessionsResponse,  LPSPDATA_ENUMSESSIONSRESPONSE, er ) \
+  ICOM_METHOD1(HRESULT, GetSPDataPointer,      LPVOID*, lplpData ) \
+  ICOM_METHOD1(HRESULT, HandleMessage,         LPSPDATA_HANDLEMESSAGE, hm ) \
+  ICOM_METHOD1(HRESULT, SendChatMessage,       LPSPDATA_CHATMESSAGE, cm ) \
+  ICOM_METHOD1(HRESULT, SetGroupName,          LPSPDATA_SETREMOTEGROUPNAME, srgn ) \
+  ICOM_METHOD1(HRESULT, SetPlayerName,         LPSPDATA_SETREMOTEPLAYERNAME, srpn ) \
+  ICOM_METHOD1(HRESULT, SetSessionDesc,        LPSPDATA_SETSESSIONDESC, ssd ) \
+  ICOM_METHOD1(HRESULT, SetSPDataPointer,      LPVOID, lpData ) \
+  ICOM_METHOD1(HRESULT, StartSession,          LPSPDATA_STARTSESSIONCOMMAND, ssc )
+
+#define IDPLobbySP_IMETHODS \
+   IUnknown_IMETHODS \
+   IDPLobbySP_METHODS
+
+ICOM_DEFINE(IDPLobbySP,IUnknown)
+#undef ICOM_INTERFACE
+
+/*** IUnknown methods ***/
+#define IDPLobbySP_QueryInterface(p,a,b)         ICOM_CALL2(QueryInterface,p,a,b)
+#define IDPLobbySP_AddRef(p)                     ICOM_CALL (AddRef,p)
+#define IDPLobbySP_Release(p)                    ICOM_CALL (Release,p)
+
+/*** IDPLobbySP methods ***/
+#define IDPLobbySP_AddGroupToGroup(p,a)          ICOM_CALL1(AddGroupToGroup,p,a)
+#define IDPLobbySP_AddPlayerToGroup(p,a)         ICOM_CALL1(AddPlayerToGroup,p,a)
+#define IDPLobbySP_CreateGroup(p,a)              ICOM_CALL1(CreateGroup,p,a)
+#define IDPLobbySP_CreateGroupInGroup(p,a)       ICOM_CALL1(CreateGroupInGroup,p,a)
+#define IDPLobbySP_DeleteGroupFromGroup(p,a)     ICOM_CALL1(DeleteGroupFromGroup,p,a)
+#define IDPLobbySP_DeletePlayerFromGroup(p,a)    ICOM_CALL1(DeletePlayerFromGroup,p,a)
+#define IDPLobbySP_DestroyGroup(p,a)             ICOM_CALL1(DestroyGroup,p,a)
+#define IDPLobbySP_EnumSessionsResponse(p,a)     ICOM_CALL1(EnumSessionsResponse,p,a)
+#define IDPLobbySP_GetSPDataPointer(p,a)         ICOM_CALL1(GetSPDataPointer,p,a)
+#define IDPLobbySP_HandleMessage(p,a)            ICOM_CALL1(HandleMessage,p,a)
+#define IDPLobbySP_SetGroupName(p,a)             ICOM_CALL1(SetGroupName,p,a)
+#define IDPLobbySP_SetPlayerName(p,a)            ICOM_CALL1(SetPlayerName,p,a)
+#define IDPLobbySP_SetSessionDesc(p,a)           ICOM_CALL1(SetSessionDesc,p,a)
+#define IDPLobbySP_StartSession(p,a)             ICOM_CALL1(StartSession,p,a)
+#define IDPLobbySP_SetSPDataPointer(p,a)         ICOM_CALL1(SetSPDataPointer,p,a)
+
+/* This variable is exported from the DLL at ordinal 6 to be accessed by the
+ * SP directly. This is the same variable that the DP SP will use.
+ */
+extern DWORD gdwDPlaySPRefCount;
+
+#endif
diff --git a/dlls/dplayx/name_server.c b/dlls/dplayx/name_server.c
index 4a3112d..8323dab 100644
--- a/dlls/dplayx/name_server.c
+++ b/dlls/dplayx/name_server.c
@@ -1,6 +1,6 @@
 /* DPLAYX.DLL name server implementation
  *
- * Copyright 2000 - Peter Hunnisett
+ * Copyright 2000-2001 - Peter Hunnisett
  *
  * <presently under construction - contact hunnise@nortelnetworks.com>
  *
@@ -43,6 +43,10 @@
   lpNSCacheData present; /* keep track of what is to be looked at when walking */
 
   DPQ_HEAD(NSCacheData) first;
+
+  BOOL bNsIsLocal;
+  LPVOID lpLocalAddrHdr;  /* FIXME: Not yet used */
+  LPVOID lpRemoteAddrHdr; /* FIXME: Not yet used */
 }; 
 typedef struct NSCache NSCache, *lpNSCache;
 
@@ -52,12 +56,22 @@
 /* Name Server functions 
  * --------------------- 
  */
-void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd )
+void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd, LPVOID lpNSInfo )
 {
 #if 0
   /* FIXME: Remove this method? */
   DPLAYX_SetLocalSession( lpsd );
 #endif
+  lpNSCache lpCache = (lpNSCache)lpNSInfo;
+
+  lpCache->bNsIsLocal = TRUE;
+}
+
+void NS_SetRemoteComputerAsNameServer( LPCDPSESSIONDESC2 lpsd, LPVOID lpNSInfo )
+{
+  lpNSCache lpCache = (lpNSCache)lpNSInfo;
+
+  lpCache->bNsIsLocal = FALSE;
 }
 
 DPQ_DECL_COMPARECB( cbUglyPig, GUID )
@@ -66,7 +80,8 @@
 }
 
 /* Store the given NS remote address for future reference */
-void NS_SetRemoteComputerAsNameServer( LPVOID                    lpNSAddrHdr,
+/* FIXME: LPDPMSG_ENUMSESSIONSREPLY should be const */
+void NS_AddRemoteComputerAsNameServer( LPCVOID                   lpcNSAddrHdr,
                                        DWORD                     dwHdrSize,
                                        LPDPMSG_ENUMSESSIONSREPLY lpMsg,
                                        LPVOID                    lpNSInfo )
@@ -75,15 +90,11 @@
   lpNSCache     lpCache = (lpNSCache)lpNSInfo;
   lpNSCacheData lpCacheNode;
 
-  TRACE( "%p, %p, %p\n", lpNSAddrHdr, lpMsg, lpNSInfo );
-
-  /* FIXME: Should check to see if the reply is for an existing session. If
-   *        so we remove the old and add the new so oldest is at front.
-   */
+  TRACE( "%p, %p, %p\n", lpcNSAddrHdr, lpMsg, lpNSInfo );
 
   /* See if we can find this session. If we can, remove it as it's a dup */
   DPQ_REMOVE_ENTRY_CB( lpCache->first, next, data->guidInstance, cbUglyPig,
-                     lpMsg->sd.guidInstance, lpCacheNode );
+                       lpMsg->sd.guidInstance, lpCacheNode );
 
   if( lpCacheNode != NULL )
   {
@@ -104,12 +115,12 @@
 
   lpCacheNode->lpNSAddrHdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                         dwHdrSize );
-  CopyMemory( lpCacheNode->lpNSAddrHdr, lpNSAddrHdr, dwHdrSize );
+  CopyMemory( lpCacheNode->lpNSAddrHdr, lpcNSAddrHdr, dwHdrSize );
               
 
   lpCacheNode->data = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(),
                                                    HEAP_ZERO_MEMORY, 
-                                                   sizeof( *lpCacheNode->data ) );
+                                                   sizeof( *(lpCacheNode->data) ) );
 
   if( lpCacheNode->data == NULL )
   {
@@ -120,8 +131,10 @@
   CopyMemory( lpCacheNode->data, &lpMsg->sd, sizeof( *lpCacheNode->data ) );
   len = WideCharToMultiByte( CP_ACP, 0, (LPWSTR)(lpMsg+1), -1, NULL, 0, NULL, NULL );
   if ((lpCacheNode->data->u1.lpszSessionNameA = HeapAlloc( GetProcessHeap(), 0, len )))
+  {
       WideCharToMultiByte( CP_ACP, 0, (LPWSTR)(lpMsg+1), -1,
                            lpCacheNode->data->u1.lpszSessionNameA, len, NULL, NULL );
+  }
 
   lpCacheNode->dwTime = timeGetTime();
 
@@ -148,8 +161,38 @@
    *        must be it. That would make this method obsolete once that's
    *        in place.
    */
-
+#if 1
   return lpCache->first.lpQHFirst->lpNSAddrHdr;
+#else
+  /* FIXME: Should convert over to this */
+  return lpCache->bNsIsLocal ? lpCache->lpLocalAddrHdr
+                             : lpCache->lpRemoteAddrHdr;
+#endif
+}
+
+/* Get the magic number associated with the Name Server */
+DWORD NS_GetNsMagic( LPVOID lpNSInfo )
+{
+  LPDWORD lpHdrInfo = (LPDWORD)NS_GetNSAddr( lpNSInfo );
+
+  return lpHdrInfo[1];
+}
+
+/* Get the magic number associated with the non NS end */
+DWORD NS_GetOtherMagic( LPVOID lpNSInfo )
+{
+  lpNSCache lpCache = (lpNSCache)lpNSInfo;
+
+  return ((LPDWORD)lpCache->lpLocalAddrHdr)[1];
+}
+
+void NS_SetLocalAddr( LPVOID lpNSInfo, LPCVOID lpHdr, DWORD dwHdrSize )
+{
+  lpNSCache lpCache = (lpNSCache)lpNSInfo;
+
+  lpCache->lpLocalAddrHdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwHdrSize );
+
+  CopyMemory( lpCache->lpLocalAddrHdr, lpHdr, dwHdrSize );
 }
 
 /* This function is responsible for sending a request for all other known
@@ -216,6 +259,9 @@
 
   /* NULL out the walking pointer */
   lpCache->present = NULL;
+
+  lpCache->bNsIsLocal = FALSE;
+
 }
 
 /* Create and initialize a session cache */
@@ -235,6 +281,8 @@
   DPQ_INIT(lpCache->first);
   lpCache->present = NULL;
 
+  lpCache->bNsIsLocal = FALSE;
+
   return TRUE;
 }
 
@@ -280,8 +328,7 @@
   lpNSCache     lpCache = lpNSInfo;
 
   const DWORD dwPresentTime = timeGetTime();
-  const DWORD dwPrunePeriod = 60000; /* is 60 secs enough? */ 
-  const DWORD dwPruneTime   = dwPresentTime - dwPrunePeriod;
+  const DWORD dwPrunePeriod = DPMSG_WAIT_60_SECS; /* is 60 secs enough? */
 
   /* This silly little algorithm is based on the fact we keep entries in 
    * the queue in a time based order. It also assumes that it is not possible
@@ -299,25 +346,12 @@
       break;
     }
 
-    if( dwPruneTime > dwPresentTime ) /* 0 <= dwPresentTime <= dwPrunePeriod */
+    /* Deal with time in a wrap around safe manner - unsigned arithmatic.
+     * Check the difference in time */
+    if( (dwPresentTime - (DPQ_FIRST(lpCache->first)->dwTime)) < dwPrunePeriod )
     {
-      if( ( DPQ_FIRST(lpCache->first)->dwTime <= dwPresentTime ) ||
-          ( DPQ_FIRST(lpCache->first)->dwTime > dwPruneTime )
-        )
-      {
-        /* Less than dwPrunePeriod old - keep */
-        break; 
-      }
-    }
-    else /* dwPrunePeriod <= dwPresentTime <= max dword */
-    {
-      if( ( DPQ_FIRST(lpCache->first)->dwTime <= dwPresentTime ) &&
-          ( DPQ_FIRST(lpCache->first)->dwTime > dwPruneTime ) 
-        )
-      {
-        /* Less than dwPrunePeriod old - keep */
-        break;
-      }
+      /* First entry has not expired yet; don't prune */
+      break;
     }
 
     lpFirstData = DPQ_FIRST(lpCache->first);
@@ -328,33 +362,38 @@
 }
 
 /* NAME SERVER Message stuff */
-void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg, 
-                                    LPDPSP_REPLYDATA lpReplyData,
+void NS_ReplyToEnumSessionsRequest( LPCVOID lpcMsg, 
+                                    LPVOID* lplpReplyData,
+                                    LPDWORD lpdwReplySize,
                                     IDirectPlay2Impl* lpDP )
 {
   LPDPMSG_ENUMSESSIONSREPLY rmsg;
   DWORD dwVariableSize;
   DWORD dwVariableLen;
-  /* LPDPMSG_ENUMSESSIONSREQUEST msg = (LPDPMSG_ENUMSESSIONSREQUEST)lpMsg; */
+  /* LPCDPMSG_ENUMSESSIONSREQUEST msg = (LPDPMSG_ENUMSESSIONSREQUEST)lpcMsg; */
   BOOL bAnsi = TRUE; /* FIXME: This needs to be in the DPLAY interface */
 
   FIXME( ": few fixed + need to check request for response\n" );
 
   if (bAnsi)
+  {
       dwVariableLen = MultiByteToWideChar( CP_ACP, 0,
                                            lpDP->dp2->lpSessionDesc->u1.lpszSessionNameA,
                                            -1, NULL, 0 );
+  }
   else
+  {
       dwVariableLen = strlenW( lpDP->dp2->lpSessionDesc->u1.lpszSessionName ) + 1;
+  }
 
   dwVariableSize = dwVariableLen * sizeof( WCHAR );
 
-  lpReplyData->dwMessageSize = lpDP->dp2->spData.dwSPHeaderSize +
-                                 sizeof( *rmsg ) + dwVariableSize;
-  lpReplyData->lpMessage     = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
-                                          lpReplyData->dwMessageSize );
+  *lpdwReplySize = lpDP->dp2->spData.dwSPHeaderSize +
+                     sizeof( *rmsg ) + dwVariableSize;
+  *lplpReplyData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                              *lpdwReplySize );
 
-  rmsg = (LPDPMSG_ENUMSESSIONSREPLY)( (BYTE*)lpReplyData->lpMessage + 
+  rmsg = (LPDPMSG_ENUMSESSIONSREPLY)( (BYTE*)*lplpReplyData + 
                                              lpDP->dp2->spData.dwSPHeaderSize);
 
   rmsg->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG; 
@@ -365,8 +404,12 @@
               sizeof( lpDP->dp2->lpSessionDesc->dwSize ) ); 
   rmsg->dwUnknown = 0x0000005c;
   if( bAnsi )
+  {
       MultiByteToWideChar( CP_ACP, 0, lpDP->dp2->lpSessionDesc->u1.lpszSessionNameA, -1,
                            (LPWSTR)(rmsg+1), dwVariableLen );
+  }
   else
+  {
       strcpyW( (LPWSTR)(rmsg+1), lpDP->dp2->lpSessionDesc->u1.lpszSessionName );
+  }
 }
diff --git a/dlls/dplayx/name_server.h b/dlls/dplayx/name_server.h
index 9c500cd..36a95a8 100644
--- a/dlls/dplayx/name_server.h
+++ b/dlls/dplayx/name_server.h
@@ -7,15 +7,20 @@
 #include "dplayx_messages.h"
 #include "dplay_global.h"
 
-void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd );
-void NS_SetRemoteComputerAsNameServer( LPVOID lpNSAddrHdr,
+void NS_SetLocalComputerAsNameServer( LPCDPSESSIONDESC2 lpsd, LPVOID lpNSInfo );
+void NS_SetRemoteComputerAsNameServer( LPCDPSESSIONDESC2 lpsd, LPVOID lpNSInfo );
+void NS_AddRemoteComputerAsNameServer( LPCVOID lpNSAddrHdr,
                                        DWORD dwHdrSize,
                                        LPDPMSG_ENUMSESSIONSREPLY lpMsg,
                                        LPVOID lpNSInfo );
 LPVOID NS_GetNSAddr( LPVOID lpNSInfo );
+DWORD NS_GetNsMagic( LPVOID lpNSInfo );
+DWORD NS_GetOtherMagic( LPVOID lpNSInfo );
+void NS_SetLocalAddr( LPVOID lpNSInfo, LPCVOID lpHdr, DWORD dwHdrSize );
 
-void NS_ReplyToEnumSessionsRequest( LPVOID lpMsg, 
-                                    LPDPSP_REPLYDATA lpReplyData,
+void NS_ReplyToEnumSessionsRequest( LPCVOID lpcMsg, 
+                                    LPVOID* lplpReplyData,
+                                    LPDWORD lpdwReplySize,
                                     IDirectPlay2Impl* lpDP );
 
 HRESULT NS_SendSessionRequestBroadcast( LPCGUID lpcGuid,
diff --git a/include/dplay.h b/include/dplay.h
index e22da01..31e11c8 100644
--- a/include/dplay.h
+++ b/include/dplay.h
@@ -1,6 +1,7 @@
 #ifndef __WINE_DPLAY_H
 #define __WINE_DPLAY_H
 
+#include "ole2.h"
 #include "wine/obj_base.h"
 
 #ifdef __cplusplus
diff --git a/include/objbase.h b/include/objbase.h
index af22e36..52c04ab 100644
--- a/include/objbase.h
+++ b/include/objbase.h
@@ -26,7 +26,9 @@
 #include <stdlib.h>
 #endif
 
+#ifndef INITGUID
 #include "cguid.h"
+#endif
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/winerror.h b/include/winerror.h
index c9857dc..8bbeed2 100644
--- a/include/winerror.h
+++ b/include/winerror.h
@@ -1464,6 +1464,8 @@
 #define S_OK                                               ((HRESULT)0L)
 #define S_FALSE                                            ((HRESULT)1L)
 
+#define E_PENDING                                          0x8000000AL
+
 
 #define E_NOTIMPL                                          0x80004001L
 #define E_NOINTERFACE                                      0x80004002L
diff --git a/ole/uuid.c b/ole/uuid.c
index b7c1c9c..0b3e6ff 100644
--- a/ole/uuid.c
+++ b/ole/uuid.c
@@ -49,3 +49,4 @@
 /* GUIDs not declared in an exported header file */
 DEFINE_GUID(IID_IDirectPlaySP,0xc9f6360,0xcc61,0x11cf,0xac,0xec,0x00,0xaa,0x00,0x68,0x86,0xe3);
 DEFINE_GUID(IID_ISFHelper,0x1fe68efb,0x1874,0x9812,0x56,0xdc,0x00,0x00,0x00,0x00,0x00,0x00);
+DEFINE_GUID(IID_IDPLobbySP,0x5a4e5a20,0x2ced,0x11d0,0xa8,0x89,0x00,0xa0,0xc9,0x05,0x43,0x3c);