- Add proper message reply mechanism and sp player data storage
- More implementation and fixes

diff --git a/dlls/dplayx/dpclassfactory.c b/dlls/dplayx/dpclassfactory.c
index 660aa3a..9a7546a 100644
--- a/dlls/dplayx/dpclassfactory.c
+++ b/dlls/dplayx/dpclassfactory.c
@@ -77,7 +77,7 @@
 
 
 /*******************************************************************************
- * DPLAYX_DllGetClassObject [DPLAYX.?]
+ * DPLAYX_DllGetClassObject [DPLAYX.11]
  * Retrieves DP or DPL class object from a DLL object
  *
  * NOTES
diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c
index 63c3a58..3ead55c 100644
--- a/dlls/dplayx/dplay.c
+++ b/dlls/dplayx/dplay.c
@@ -160,6 +160,8 @@
           ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
             LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_InitializeConnection
+          ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
     LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
     DWORD dwFlags, LPVOID lpContext );
@@ -174,7 +176,7 @@
                                 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
 
 
-static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData );
+static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
 
 
 
@@ -241,6 +243,7 @@
 
   DPQ_INIT(This->dp2->receiveMsgs);
   DPQ_INIT(This->dp2->sendMsgs);
+  DPQ_INIT(This->dp2->replysExpected);
 
   if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
   {
@@ -504,14 +507,14 @@
   TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
 
   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
-                       sizeof( IDirectPlay2Impl ) );
+                       sizeof( *This ) );
 
   if( *ppvObj == NULL )
   {
     return DPERR_OUTOFMEMORY;
   }
 
-  CopyMemory( *ppvObj, iface, sizeof( IDirectPlay2Impl )  );
+  CopyMemory( *ppvObj, This, sizeof( *This )  );
   (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
 
   if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
@@ -613,25 +616,22 @@
 }
 
 /* *lplpReply will be non NULL iff there is something to reply */
-HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
-                          DWORD  dwMessageBodySize, LPCVOID lpMessageHeader,
+HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
+                          DWORD  dwMessageBodySize, LPCVOID lpcMessageHeader,
                           WORD wCommandId, WORD wVersion, 
                           LPVOID* lplpReply, LPDWORD lpdwMsgSize )
 {
   TRACE( "(%p)->(%p,0x%08lx,%p,%u,%u)\n",
-         This, lpMessageBody, dwMessageBodySize, lpMessageHeader, wCommandId, 
+         This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId, 
          wVersion );
 
-  DebugBreak();
-
   switch( wCommandId )
   {
     case DPMSGCMD_REQUESTNEWPLAYERID:
     {
-#if 0
       LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = 
-        (LPCDPMSG_REQUESTNEWPLAYERID)lpMessageBody;
-#endif
+        (LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody;
+
       LPDPMSG_NEWPLAYERIDREPLY lpReply;
 
       *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
@@ -640,25 +640,8 @@
                                                         HEAP_ZERO_MEMORY,
                                                         *lpdwMsgSize );
 
-      FIXME( "Ignoring dwFlags in request msg\n" );
-
-#if 0
-      /* This is just a test. See how large the SPData is and send it */
-      {
-        LPVOID lpData;
-        DWORD  dwDataSize;
-        HRESULT hr;
-
-        hr = IDirectPlaySP_GetSPData( This->dp2->spData.lpISP, &lpData,
-                                      &dwDataSize, DPSET_REMOTE );
-
-        if( FAILED(hr) )
-        {
-          ERR( "Unable to get remote SPData %s\n", DPLAYX_HresultToString(hr) );
-        }
-
-      }
-#endif
+      FIXME( "Ignoring dwFlags 0x%08lx in request msg\n",
+             lpcMsg->dwFlags );
 
       /* Setup the reply */
       lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) + 
@@ -676,29 +659,25 @@
       break;
     }
 
+    case DPMSGCMD_GETNAMETABLEREPLY:
     case DPMSGCMD_NEWPLAYERIDREPLY:
     {
 
-      if( This->dp2->hMsgReceipt )
-      {
-        /* This is a hack only */
-        This->dp2->lpMsgReceived = HeapAlloc( GetProcessHeap(), 
-                                              HEAP_ZERO_MEMORY,
-                                              dwMessageBodySize );
-        CopyMemory( This->dp2->lpMsgReceived, lpMessageBody, dwMessageBodySize );
-        SetEvent( This->dp2->hMsgReceipt );
-      }
-      else
-      {
-        ERR( "No receipt event set - only expecting in reply mode\n" );
-      }
+      DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
  
       break;
     }
+    
+    case DPMSGCMD_FORWARDADDPLAYERNACK:
+    {
+      DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
+      break;
+    }
 
     default:
     {
       FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
+      DebugBreak();
       break;
     }
   }
@@ -873,6 +852,8 @@
   /* FIXME: Should we validate the dwFlags? */
   lpGData->dwFlags = dwFlags;
 
+  TRACE( "Created group id 0x%08lx\n", *lpid );
+
   return lpGData;
 }
 
@@ -968,6 +949,7 @@
   if( DPID_SYSTEM_GROUP == *lpidGroup )
   {
     This->dp2->lpSysGroup = lpGData; 
+    TRACE( "Inserting system group\n" );
   }
   else
   {
@@ -1149,6 +1131,11 @@
     }
   }
 
+  /* Initialize the SP data section */
+  lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
+
+  TRACE( "Created player id 0x%08lx\n", *lpid );
+
   return lpPData;
 }
 
@@ -1325,6 +1312,7 @@
   HANDLE hr = DP_OK;
   lpPlayerData lpPData;
   lpPlayerList lpPList;
+  DWORD dwCreateFlags = 0;
 
   TRACE( "(%p)->(%p,%p,%d,%p,0x%08lx,0x%08lx,%u)\n", 
          This, lpidPlayer, lpPlayerName, hEvent, lpData, 
@@ -1340,6 +1328,35 @@
     return DPERR_INVALIDPARAMS;
   }
 
+
+  /* Determine the creation flags for the player. These will be passed
+   * to the name server if requesting a player id and to the SP when
+   * informing it of the player creation
+   */
+  {
+    if( dwFlags & DPPLAYER_SERVERPLAYER )
+    {
+      if( *lpidPlayer == DPID_SERVERPLAYER )
+      {
+        /* Server player for the host interface */
+        dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
+      }
+      else if( *lpidPlayer == DPID_NAME_SERVER )
+      {
+        /* Name server - master of everything */
+        dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
+      }
+      else
+      {
+        /* Server player for a non host interface */
+        dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
+      }
+    }
+
+    if( lpMsgHdr == NULL )
+      dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
+  }
+
   /* Verify we know how to handle all the flags */
   if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
          ( dwFlags & DPPLAYER_SPECTATOR )
@@ -1360,7 +1377,7 @@
     }
     else
     {
-      hr = DP_MSG_SendRequestPlayerId( This, dwFlags, lpidPlayer );
+      hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
 
       if( FAILED(hr) )
       {
@@ -1376,6 +1393,7 @@
      */
   }
 
+  /* FIXME: Should we be storing these dwFlags or the creation ones? */
   lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags,
                              hEvent, bAnsi );
 
@@ -1406,28 +1424,15 @@
   if( This->dp2->spData.lpCB->CreatePlayer )
   {
     DPSP_CREATEPLAYERDATA data;
-    DWORD dwCreateFlags = 0;
-
-    TRACE( "Calling SP CreatePlayer\n" );
-
-    if( ( dwFlags & DPPLAYER_SERVERPLAYER ) &&
-        ( *lpidPlayer == DPID_SERVERPLAYER )
-      )
-      dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
-
-    if( ( dwFlags & DPPLAYER_SERVERPLAYER ) &&
-        ( *lpidPlayer == DPID_NAME_SERVER ) 
-      )
-      dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
-
-    if( lpMsgHdr == NULL )
-      dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
 
     data.idPlayer          = *lpidPlayer;
     data.dwFlags           = dwCreateFlags;
     data.lpSPMessageHeader = lpMsgHdr;
     data.lpISP             = This->dp2->spData.lpISP;
 
+    TRACE( "Calling SP CreatePlayer 0x%08lx: dwFlags: 0x%08lx lpMsgHdr: %p\n",
+           *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
+
     hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
   }
 
@@ -1453,11 +1458,22 @@
 
   if( FAILED(hr) )
   {
-    ERR( "Failed to add player to sys groupwith sp: %s\n", 
+    ERR( "Failed to add player to sys group with sp: %s\n", 
          DPLAYX_HresultToString(hr) );
     return hr;
   }
 
+#if 1
+  if( This->dp2->bHostInterface == FALSE )
+  {
+    /* Let the name server know about the creation of this player */
+    /* FIXME: Is this only to be done for the creation of a server player or
+     *        is this used for regular players? If only for server players, move
+     *        this call to DP_SecureOpen(...);
+     */
+    hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
+  }
+#else
   /* Inform all other peers of the creation of a new player. If there are
    * no peers keep this quiet. 
    * Also, if this was a remote event, no need to rebroadcast it.
@@ -1484,6 +1500,7 @@
     hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, 
                     sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
   }
+#endif
 
   return hr;
 }
@@ -2055,7 +2072,8 @@
   /* Does a thread exist? If so we were doing an async enum session */
   if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
   {
-    TRACE( "Killing EnumSession thread\n" );
+    TRACE( "Killing EnumSession thread %u\n", 
+           This->dp2->hEnumSessionThread );
 
     /* Request that the thread kill itself nicely */
     SetEvent( This->dp2->hKillEnumSessionThreadEvent );
@@ -2094,7 +2112,12 @@
     DP_IF_GetCaps( This, &spCaps, 0 );
     dwTimeout = spCaps.dwTimeout;
 
-    /* FIXME: If it's still 0, we need to provide the IP default */
+    /* The service provider doesn't provide one either! */
+    if( dwTimeout == 0 )
+    {
+      /* Provide the TCP/IP default */
+      dwTimeout = DPMSG_WAIT_5_SECS;
+    }
   }
 
   if( dwFlags & DPENUMSESSIONS_STOPASYNC )
@@ -2725,6 +2748,7 @@
     hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL, 
                              0, 
                              DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
+
   }
   else if( dwFlags & DPOPEN_CREATE )
   {
@@ -3792,7 +3816,7 @@
 
 
 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
-static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData )
+static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
 {
   UINT i; 
   LPCSTR spSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
@@ -3814,6 +3838,7 @@
     FILETIME filetime;
 
     (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
+    *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
     
 
     /* Need to loop over the service providers in the registry */
@@ -3910,6 +3935,7 @@
         continue;
       }
 
+      TRACE( "Loading %s\n", returnBuffer ); 
       return LoadLibraryA( returnBuffer );
     }
   }
@@ -3917,18 +3943,17 @@
   return 0;
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
-          ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
+static HRESULT WINAPI DP_IF_InitializeConnection
+          ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
 {
   HMODULE hServiceProvider;
   HRESULT hr;
   LPDPSP_SPINIT SPInit;
   GUID guidSP;
-  DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
+  const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
+  BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
 
-  ICOM_THIS(IDirectPlay3Impl,iface);
-
-  TRACE("(%p)->(%p,0x%08lx)\n", This, lpConnection, dwFlags );
+  TRACE("(%p)->(%p,0x%08lx,%u)\n", This, lpConnection, dwFlags, bAnsi );
 
   if( dwFlags != 0 )
   {
@@ -3958,7 +3983,7 @@
   This->dp2->spData.lpGuid = &guidSP;
 
   /* Load the service provider */
-  hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData );
+  hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
 
   if( hServiceProvider == 0 )
   {
@@ -3966,22 +3991,35 @@
     return DPERR_UNAVAILABLE; 
   }
   
-  /* Initialize the service provider by calling SPInit */
-  SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
-
+  if( bIsDpSp )
+  {
+    /* Initialize the service provider by calling SPInit */
+    SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
+  }
+  else
+  {
+    /* Initialize the service provider by calling SPInit */
+    SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "DPLSPInit" );    
+  }
+  
   if( SPInit == NULL )
   {
-    ERR( "Service provider doesn't provide SPInit interface?\n" );
+    ERR( "Service provider doesn't provide %s interface?\n",
+         bIsDpSp ? "SPInit" : "DPLSPInit" );
     FreeLibrary( hServiceProvider );
     return DPERR_UNAVAILABLE;
   }  
 
-  TRACE( "Calling SPInit\n" );
+  TRACE( "Calling %s (SP entry point)\n", bIsDpSp ? "SPInit" : "DPLSPInit" );
+  
+  /* FIXME: Need to break this out into a seperate routine for DP SP and
+   *        DPL SP as they actually use different stuff... 
+   */
   hr = (*SPInit)( &This->dp2->spData );
 
   if( FAILED(hr) )
   {
-    ERR( "SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
+    ERR( "DP/DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
     FreeLibrary( hServiceProvider );
     return hr;
   }
@@ -3995,12 +4033,18 @@
   return DP_OK;
 }
 
+static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
+          ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
+{
+  ICOM_THIS(IDirectPlay3Impl,iface);
+  return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );  
+}
+
 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
           ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay3Impl,iface);
-  FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpConnection, dwFlags );
-  return DP_OK;
+  return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
 }
 
 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
@@ -4846,9 +4890,42 @@
 };
 #undef XCAST
 
+extern 
+HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP, 
+                            DPID idPlayer, 
+                            LPVOID* lplpData )
+{
+  lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
+
+  if( lpPlayer == NULL )
+  {
+    return DPERR_INVALIDPLAYER;
+  }
+
+  *lplpData = lpPlayer->lpPData->lpSPPlayerData;
+
+  return DP_OK;
+}
+
+extern 
+HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP, 
+                            DPID idPlayer, 
+                            LPVOID lpData )
+{
+  lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
+
+  if( lpPlayer == NULL )
+  {
+    return DPERR_INVALIDPLAYER;
+  }
+
+  lpPlayer->lpPData->lpSPPlayerData = lpData;
+
+  return DP_OK;
+}
 
 /***************************************************************************
- *  DirectPlayEnumerateA (DPLAYX.2) 
+ *  DirectPlayEnumerateA [DPLAYX.2][DPLAYX.9][DPLAY.2] 
  *
  *  The pointer to the structure lpContext will be filled with the 
  *  appropriate data for each service offered by the OS. These services are
@@ -4980,7 +5057,7 @@
 }
 
 /***************************************************************************
- *  DirectPlayEnumerateW (DPLAYX.3)
+ *  DirectPlayEnumerateW [DPLAYX.3]
  *
  */
 HRESULT WINAPI DirectPlayEnumerateW( LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
@@ -5027,7 +5104,7 @@
 
 
 /***************************************************************************
- *  DirectPlayCreate (DPLAYX.1) (DPLAY.1)
+ *  DirectPlayCreate [DPLAYX.1][DPLAY.1]
  *
  */
 HRESULT WINAPI DirectPlayCreate
@@ -5044,7 +5121,6 @@
     return CLASS_E_NOAGGREGATION;
   }
 
-
   /* Create an IDirectPlay object. We don't support that so we'll cheat and
      give them an IDirectPlay2A object and hope that doesn't cause problems */
   if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
diff --git a/dlls/dplayx/dplay_global.h b/dlls/dplayx/dplay_global.h
index 0cfc5f5..b7daa74 100644
--- a/dlls/dplayx/dplay_global.h
+++ b/dlls/dplayx/dplay_global.h
@@ -35,6 +35,21 @@
   HANDLE       hSuicideRequest;
 } EnumSessionAsyncCallbackData;
 
+typedef struct tagDP_MSG_REPLY_STRUCT
+{
+  HANDLE hReceipt;
+  WORD   wExpectedReply;
+  LPVOID lpReplyMsg;
+  DWORD  dwMsgBodySize;
+  /* FIXME: Is the message header required as well? */
+} DP_MSG_REPLY_STRUCT, *LPDP_MSG_REPLY_STRUCT;
+
+typedef struct tagDP_MSG_REPLY_STRUCT_LIST
+{
+  DPQ_ENTRY(tagDP_MSG_REPLY_STRUCT_LIST) replysExpected; 
+  DP_MSG_REPLY_STRUCT replyExpected;
+} DP_MSG_REPLY_STRUCT_LIST, *LPDP_MSG_REPLY_STRUCT_LIST;
+
 struct PlayerData
 {
   /* Individual player information */
@@ -53,6 +68,9 @@
   LPVOID lpRemoteData;
   DWORD  dwRemoteDataSize;
 
+  /* SP data on a per player basis */
+  LPVOID lpSPPlayerData;
+
   DWORD  dwFlags; /* Special remarks about the type of player */
 };
 typedef struct PlayerData* lpPlayerData;
@@ -137,10 +155,8 @@
 
   BOOL bConnectionInitialized;
 
-
-  /* proof of concept for message reception */
-  HANDLE hMsgReceipt;
-  LPVOID lpMsgReceived;
+  /* Expected messages queue */
+  DPQ_HEAD( tagDP_MSG_REPLY_STRUCT_LIST ) replysExpected;
 } DirectPlay2Data;
 
 typedef struct tagDirectPlay3Data
@@ -192,5 +208,11 @@
                           WORD wCommandId, WORD wVersion, 
                           LPVOID* lplpReply, LPDWORD lpdwMsgSize );
 
+/* DP SP external interfaces into DirectPlay */
+extern HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP, DPID idPlayer, LPVOID* lplpData );
+extern HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP, DPID idPlayer, LPVOID lpData );
+
+/* DP external interfaces to call into DPSP interface */
+extern LPVOID DPSP_CreateSPPlayerData(void);
 
 #endif /* __WINE_DPLAY_GLOBAL_INCLUDED */
diff --git a/dlls/dplayx/dplaysp.c b/dlls/dplayx/dplaysp.c
index 2a21a01..b1a8a18 100644
--- a/dlls/dplayx/dplaysp.c
+++ b/dlls/dplayx/dplaysp.c
@@ -26,7 +26,6 @@
 static BOOL DPSP_CreateDirectPlaySP( LPVOID lpSP, IDirectPlay2Impl* dp );
 static BOOL DPSP_DestroyDirectPlaySP( LPVOID lpSP );
 
-
 /* Predefine the interface */
 typedef struct IDirectPlaySPImpl IDirectPlaySPImpl;
 
@@ -46,8 +45,6 @@
 
   IDirectPlay2Impl* dplay; /* FIXME: This should perhaps be iface not impl */
 
-  LPVOID lpPlayerData; /* FIXME: Need to figure out how this actually behaves */
-  DWORD dwPlayerDataSize;
 } DirectPlaySPData;
 
 #define DPSP_IMPL_FIELDS \
@@ -64,7 +61,15 @@
 /* Forward declaration of virtual tables */
 static ICOM_VTABLE(IDirectPlaySP) directPlaySPVT;
 
+/* This structure is passed to the DP object for safe keeping */
+typedef struct tagDP_SPPLAYERDATA
+{
+  LPVOID lpPlayerLocalData;
+  DWORD  dwPlayerLocalDataSize;
 
+  LPVOID lpPlayerRemoteData;
+  DWORD  dwPlayerRemoteDataSize;
+} DP_SPPLAYERDATA, *LPDP_SPPLAYERDATA;
 
 /* Create the SP interface */
 extern
@@ -165,6 +170,15 @@
    */
   /* IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp ); */
 
+  /* 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;
 }
 
@@ -200,14 +214,14 @@
   TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
 
   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
-                       sizeof( IDirectPlaySPImpl ) );
+                       sizeof( *This ) );
 
   if( *ppvObj == NULL )
   {
     return DPERR_OUTOFMEMORY;
   }
 
-  CopyMemory( *ppvObj, iface, sizeof( IDirectPlaySPImpl )  );
+  CopyMemory( *ppvObj, This, sizeof( *This )  );
   (*(IDirectPlaySPImpl**)ppvObj)->ulInterfaceRef = 0;
 
   if( IsEqualGUID( &IID_IDirectPlaySP, riid ) )
@@ -363,18 +377,50 @@
   DWORD dwFlags
 )
 {
+  HRESULT hr;
+  LPDP_SPPLAYERDATA lpPlayerData;
   ICOM_THIS(IDirectPlaySPImpl,iface);
 
-  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
-  FIXME( "(%p)->(0x%08lx,%p,%p,0x%08lx): stub\n", 
+/*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
+  TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx)\n", 
          This, idPlayer, lplpData, lpdwDataSize, dwFlags );
 
+  hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerData );
+
+  if( FAILED(hr) )
+  {
+    TRACE( "Couldn't get player data: %s\n", DPLAYX_HresultToString(hr) );
+    return DPERR_INVALIDPLAYER;
+  }
+
   /* What to do in the case where there is nothing set yet? */
+  if( dwFlags == DPSET_LOCAL )
+  {
+    if( lpPlayerData->lpPlayerLocalData )
+    {
+      HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerLocalData );
+    }
 
-  *lplpData     = This->sp->lpPlayerData;
-  *lpdwDataSize = This->sp->dwPlayerDataSize;
+    *lplpData     = lpPlayerData->lpPlayerLocalData;
+    *lpdwDataSize = lpPlayerData->dwPlayerLocalDataSize;
+  }
+  else if( dwFlags == DPSET_REMOTE )
+  {
+    if( lpPlayerData->lpPlayerRemoteData )
+    {
+      HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerRemoteData );
+    }
 
-  return DP_OK;
+    *lplpData     = lpPlayerData->lpPlayerRemoteData;
+    *lpdwDataSize = lpPlayerData->dwPlayerRemoteDataSize;
+  }
+
+  if( *lplpData == NULL )
+  {
+    hr = DPERR_GENERIC;
+  } 
+
+  return hr;
 }
 
 static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
@@ -391,7 +437,7 @@
 
   ICOM_THIS(IDirectPlaySPImpl,iface);
 
-  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
+/*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
   FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n", 
          This, lpMessageBody, dwMessageBodySize, lpMessageHeader );
 
@@ -409,6 +455,7 @@
   switch( lpMsg->wCommandId )
   {
     /* Name server needs to handle this request */
+    /* FIXME: This should be done in direct play handler */
     case DPMSGCMD_ENUMSESSIONSREQUEST:
     {
       DPSP_REPLYDATA data;
@@ -430,6 +477,7 @@
     }
 
     /* Name server needs to handle this request */
+    /* FIXME: This should be done in direct play handler */
     case DPMSGCMD_ENUMSESSIONSREPLY:
     {
       NS_SetRemoteComputerAsNameServer( lpMessageHeader, 
@@ -438,14 +486,13 @@
                                         This->sp->dplay->dp2->lpNameServerData );
 
       /* No reply expected */
+      hr = DP_OK;
 
       break;
     }
 
-    case DPMSGCMD_GETNAMETABLE:
-    case DPMSGCMD_GETNAMETABLEREPLY:
-    case DPMSGCMD_NEWPLAYERIDREPLY:
-    case DPMSGCMD_REQUESTNEWPLAYERID:
+    /* Pass everything else to Direct Play */
+    default:
     {
       DPSP_REPLYDATA data;
       
@@ -453,9 +500,9 @@
       data.dwMessageSize = 0;
 
       /* Pass this message to the dplay interface to handle */
-      DP_HandleMessage( This->sp->dplay, lpMessageBody, dwMessageBodySize,
-                        lpMessageHeader, wCommandId, wVersion, 
-                        &data.lpMessage, &data.dwMessageSize );
+      hr = DP_HandleMessage( This->sp->dplay, lpMessageBody, dwMessageBodySize,
+                             lpMessageHeader, wCommandId, wVersion, 
+                             &data.lpMessage, &data.dwMessageSize );
 
       /* Do we want a reply? */
       if( data.lpMessage != NULL )
@@ -476,10 +523,6 @@
 
       break;
     }
-
-    default:
-      FIXME( "Unknown Command of %u and size 0x%08lx\n", 
-             lpMsg->wCommandId, dwMessageBodySize );
   }
 
 #if 0
@@ -736,22 +779,40 @@
   DWORD dwFlags
 )
 {
+  HRESULT           hr;
+  LPDP_SPPLAYERDATA lpPlayerEntry;
+  LPVOID            lpPlayerData; 
+
   ICOM_THIS(IDirectPlaySPImpl,iface);
 
-  /* FIXME: I'm not sure if this stuff should be associated with the DPlay
-   *        player lists. How else would this stuff get deleted? 
-   */
-
-  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
-  FIXME( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx): stub\n", 
+/*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
+  TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx)\n", 
          This, idPlayer, lpData, dwDataSize, dwFlags );
 
-  This->sp->lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize ); 
+  hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerEntry );
+  if( FAILED(hr) )
+  {
+    /* Player must not exist */
+    return DPERR_INVALIDPLAYER;
+  }
 
-  This->sp->dwPlayerDataSize = dwDataSize;
-  CopyMemory( This->sp->lpPlayerData, lpData, dwDataSize );
+  lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
+  CopyMemory( lpPlayerData, lpData, dwDataSize );
 
-  return DP_OK;
+  if( dwFlags == DPSET_LOCAL )
+  {
+    lpPlayerEntry->lpPlayerLocalData = lpPlayerData;
+    lpPlayerEntry->dwPlayerLocalDataSize = dwDataSize;
+  }
+  else if( dwFlags == DPSET_REMOTE )
+  {
+    lpPlayerEntry->lpPlayerRemoteData = lpPlayerData;
+    lpPlayerEntry->dwPlayerRemoteDataSize = dwDataSize;
+  }
+
+  hr = DP_SetSPPlayerData( This->sp->dplay, idPlayer, lpPlayerEntry );
+
+  return hr;
 }
 
 static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress
@@ -777,15 +838,16 @@
   DWORD dwFlags
 )
 {
+  HRESULT hr = DP_OK;
   ICOM_THIS(IDirectPlaySPImpl,iface);
 
-  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
+/*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
   TRACE( "(%p)->(%p,%p,0x%08lx)\n", 
          This, lplpData, lpdwDataSize, dwFlags );
 
 #if 0
   /* This is what the documentation says... */
-  if( dwFlags != 0 )
+  if( dwFlags != DPSET_REMOTE )
   {
     return DPERR_INVALIDPARAMS;
   }
@@ -794,7 +856,7 @@
   /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
    * thing?
    */
-  if( dwFlags != 0 )
+  if( dwFlags != DPSET_REMOTE )
   {
     FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
   }
@@ -807,14 +869,24 @@
   {
     *lpdwDataSize = This->sp->dwSpRemoteDataSize;
     *lplpData     = This->sp->lpSpRemoteData;
+
+    if( This->sp->lpSpRemoteData == NULL )
+    {
+      hr = DPERR_GENERIC;
+    }
   }
   else if( dwFlags == DPSET_LOCAL )
   {
     *lpdwDataSize = This->sp->dwSpLocalDataSize;
     *lplpData     = This->sp->lpSpLocalData;
+
+    if( This->sp->lpSpLocalData == NULL )
+    {
+      hr = DPERR_GENERIC;
+    }
   }
 
-  return DP_OK;
+  return hr;
 }
 
 static HRESULT WINAPI IDirectPlaySPImpl_SetSPData
@@ -828,13 +900,13 @@
 
   ICOM_THIS(IDirectPlaySPImpl,iface);
 
-  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
+/*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
   TRACE( "(%p)->(%p,0x%08lx,0x%08lx)\n", 
          This, lpData, dwDataSize, dwFlags );
 
 #if 0
   /* This is what the documentation says... */
-  if( dwFlags != 0 )
+  if( dwFlags != DPSET_REMOTE )
   {
     return DPERR_INVALIDPARAMS;
   }
@@ -843,35 +915,23 @@
   /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
    * thing?
    */
-  if( dwFlags != 0 )
+  if( dwFlags != DPSET_REMOTE )
   {
     FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
   }
 #endif
 
-  if( dwFlags == DPSET_REMOTE )
-  {
-    lpSpData = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, dwDataSize );
-  }  
-  else
-  {
-    lpSpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize ); 
-  }
-
+  lpSpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
   CopyMemory( lpSpData, lpData, dwDataSize );
 
   /* If we have data already allocated, free it and replace it */
   if( dwFlags == DPSET_REMOTE )
   {
-    /* FIXME: This doesn't strictly make sense as there is no means to share
-     *        this shared data. Must be misinterpreting something...
-     */
     if( This->sp->lpSpRemoteData )
     {
-      DPLAYX_PrivHeapFree( This->sp->lpSpRemoteData );
+      HeapFree( GetProcessHeap(), 0, This->sp->lpSpRemoteData );
     }
 
-    /* NOTE: dwDataSize is also stored in the heap structure */
     This->sp->dwSpRemoteDataSize = dwDataSize;
     This->sp->lpSpRemoteData = lpSpData;
   }
@@ -923,3 +983,15 @@
   IDirectPlaySPImpl_SetSPData,
   IDirectPlaySPImpl_SendComplete
 };
+
+
+/* DP external interfaces to call into DPSP interface */
+
+/* Allocate the structure */
+extern LPVOID DPSP_CreateSPPlayerData(void)
+{
+  TRACE( "Creating SPPlayer data struct\n" );
+  return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
+                    sizeof( DP_SPPLAYERDATA ) );
+}
+
diff --git a/dlls/dplayx/dplayx_messages.c b/dlls/dplayx/dplayx_messages.c
index 4f63d01..0d24d3c 100644
--- a/dlls/dplayx/dplayx_messages.c
+++ b/dlls/dplayx/dplayx_messages.c
@@ -27,8 +27,11 @@
   HANDLE hNotifyEvent; 
 } MSGTHREADINFO, *LPMSGTHREADINFO;
 
-
 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext );
+static LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA data, 
+                                  DWORD dwWaitTime, WORD wReplyCommandId,
+                                  LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
+
 
 /* Create the message reception thread to allow the application to receive
  * asynchronous message reception
@@ -139,6 +142,42 @@
   return 0;
 }
 
+/* DP messageing stuff */
+static HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
+                                              LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, 
+                                              WORD wReplyCommandId );
+static LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
+                                       LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
+
+
+static
+HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
+                                       LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, WORD wReplyCommandId )
+{
+  lpReplyStructList->replyExpected.hReceipt       = CreateEventA( NULL, FALSE, FALSE, NULL );
+  lpReplyStructList->replyExpected.wExpectedReply = wReplyCommandId;
+  lpReplyStructList->replyExpected.lpReplyMsg     = NULL;
+  lpReplyStructList->replyExpected.dwMsgBodySize  = 0;
+
+  /* Insert into the message queue while locked */
+  EnterCriticalSection( &This->unk->DP_lock );
+    DPQ_INSERT( This->dp2->replysExpected, lpReplyStructList, replysExpected );
+  LeaveCriticalSection( &This->unk->DP_lock );
+
+  return lpReplyStructList->replyExpected.hReceipt;
+}
+
+static
+LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
+                                LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize  )
+{
+  CloseHandle( lpReplyStructList->replyExpected.hReceipt );
+
+  *lplpReplyMsg    = lpReplyStructList->replyExpected.lpReplyMsg;
+  *lpdwMsgBodySize = lpReplyStructList->replyExpected.dwMsgBodySize;
+
+  return lpReplyStructList->replyExpected.lpReplyMsg;
+}
 
 HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
                                     LPDPID lpdpidAllocatedId )
@@ -146,7 +185,6 @@
   LPVOID                     lpMsg;
   LPDPMSG_REQUESTNEWPLAYERID lpMsgBody;
   DWORD                      dwMsgSize;
-  DWORD                      dwWaitReturn;
   HRESULT                    hr = DP_OK;
 
   dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
@@ -156,19 +194,16 @@
   lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg + 
                                              This->dp2->spData.dwSPHeaderSize );
 
+  /* Compose dplay message envelope */
   lpMsgBody->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG;
   lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID;
   lpMsgBody->envelope.wVersion   = DPMSGVER_DP6;
 
+  /* Compose the body of the message */
   lpMsgBody->dwFlags = dwFlags;
 
-  /* FIXME: Need to have a more advanced queuing system as this needs to
-   *        block on send until we get response. Otherwise we need to be
-   *        able to ensure we can pick out the exact response. Of course,
-   *        with something as non critical as this, would it matter? The
-   *        id has been effectively reserved for this session...
-   */
-  { 
+  /* Send the message */
+  {
     DPSP_SENDDATA data;
 
     data.dwFlags        = DPSEND_GUARANTEED;
@@ -179,37 +214,20 @@
     data.bSystemMessage = TRUE; /* Allow reply to be sent */
     data.lpISP          = This->dp2->spData.lpISP;
 
-    /* Setup for receipt */
-    This->dp2->hMsgReceipt = CreateEventA( NULL, FALSE, FALSE, NULL );
+    TRACE( "Asking for player id w/ dwFlags 0x%08lx\n", 
+           lpMsgBody->dwFlags );
 
-    TRACE( "Sending request for player id\n" );
- 
-    hr = (*This->dp2->spData.lpCB->Send)( &data );
 
-    if( FAILED(hr) )
-    {
-      ERR( "Request for new playerID send failed: %s\n",
-           DPLAYX_HresultToString( hr ) );
-      return DPERR_NOCONNECTION;
-    }
+    DP_MSG_ExpectReply( This, &data, DPMSG_DEFAULT_WAIT_TIME, DPMSGCMD_NEWPLAYERIDREPLY, 
+                        &lpMsg, &dwMsgSize );
   }
 
-  dwWaitReturn = WaitForSingleObject( This->dp2->hMsgReceipt, 30000 );
-  if( dwWaitReturn != WAIT_OBJECT_0 )
-  {
-    ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
-    hr = DPERR_TIMEOUT;
-  }
-
-  CloseHandle( This->dp2->hMsgReceipt );
-  This->dp2->hMsgReceipt = 0;
-
   /* Need to examine the data and extract the new player id */
   if( !FAILED(hr) )
   {
     LPCDPMSG_NEWPLAYERIDREPLY lpcReply; 
 
-    lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)This->dp2->lpMsgReceived;
+    lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)lpMsg;
 
     *lpdpidAllocatedId = lpcReply->dpidNewPlayerId;   
 
@@ -217,47 +235,217 @@
 
     /* FIXME: I think that the rest of the message has something to do
      *        with remote data for the player that perhaps I need to setup.
+     *        However, with the information that is passed, all that it could
+     *        be used for is a standardized intialization value, which I'm 
+     *        guessing we can do without. Unless the message content is the same
+     *        for several different messages?
      */
-#if 0
-   /* Set the passed service provider data */
-   IDirectPlaySP_SetSPData( This->dp2->spData.lpISP, data, 
-                            msgsize, DPSET_REMOTE );
 
-#endif
-
-    HeapFree( GetProcessHeap(), 0, This->dp2->lpMsgReceived ); 
-    This->dp2->lpMsgReceived = NULL;
+    HeapFree( GetProcessHeap(), 0, lpMsg ); 
   }
 
   return hr;
 }
 
-
-/* This function seems to cause a trap in the SP. It would seem unnecessary */
-/* FIXME: Remove this method if not required */
-HRESULT DP_MSG_OpenStream( IDirectPlay2AImpl* This )
+HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer )
 {
-  HRESULT       hr;
-  DPSP_SENDDATA data;
+  LPVOID                   lpMsg;
+  LPDPMSG_FORWARDADDPLAYER lpMsgBody;
+  DWORD                    dwMsgSize;
+  HRESULT                  hr = DP_OK;
 
-  data.dwFlags        = DPSEND_OPENSTREAM;
-  data.idPlayerTo     = 0; /* Name server */
-  data.idPlayerFrom   = 0; /* From DP itself */
-  data.lpMessage      = NULL;
-  data.dwMessageSize  = This->dp2->spData.dwSPHeaderSize;
-  data.bSystemMessage = FALSE; /* FIXME? */
-  data.lpISP          = This->dp2->spData.lpISP;
+  dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
 
-  hr = (*This->dp2->spData.lpCB->Send)( &data );
+  lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
+
+  lpMsgBody = (LPDPMSG_FORWARDADDPLAYER)( (BYTE*)lpMsg +
+                                          This->dp2->spData.dwSPHeaderSize );
+
+  /* Compose dplay message envelope */
+  lpMsgBody->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG;
+  lpMsgBody->envelope.wCommandId = DPMSGCMD_FORWARDADDPLAYER;
+  lpMsgBody->envelope.wVersion   = DPMSGVER_DP6;
+
+#if 0
+  {
+    LPBYTE lpPData;
+    DWORD  dwDataSize;
+    
+    /* SP Player remote data needs to be propagated at some point - is this the point? */
+    IDirectPlaySP_GetSPPlayerData( This->dp2->spData.lpISP, dpidServer, (LPVOID*)&lpPData, &dwDataSize, DPSET_REMOTE );
+    
+    ERR( "Player Data size is 0x%08lx\n"
+         "[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n"
+         "[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n", 
+ 
+	 dwDataSize,
+         lpPData[0], lpPData[1], lpPData[2], lpPData[3], lpPData[4],
+	 lpPData[5], lpPData[6], lpPData[7], lpPData[8], lpPData[9],
+         lpPData[10], lpPData[11], lpPData[12], lpPData[13], lpPData[14],
+	 lpPData[15], lpPData[16], lpPData[17], lpPData[18], lpPData[19],
+         lpPData[20], lpPData[21], lpPData[22], lpPData[23], lpPData[24],
+	 lpPData[25], lpPData[26], lpPData[27], lpPData[28], lpPData[29],
+         lpPData[30], lpPData[31]	 	 
+        );
+    DebugBreak();
+  }
+#endif
+
+  /* Compose body of message */
+  lpMsgBody->dpidAppServer = dpidServer;
+  lpMsgBody->unknown2[0] = 0x0;
+  lpMsgBody->unknown2[1] = 0x1c;
+  lpMsgBody->unknown2[2] = 0x6c;
+  lpMsgBody->unknown2[3] = 0x50;
+  lpMsgBody->unknown2[4] = 0x9;
+
+  lpMsgBody->dpidAppServer2 = dpidServer;
+  lpMsgBody->unknown3[0] = 0x0;
+  lpMsgBody->unknown3[0] = 0x0;
+  lpMsgBody->unknown3[0] = 0x20;
+  lpMsgBody->unknown3[0] = 0x0;
+  lpMsgBody->unknown3[0] = 0x0;
+  
+  lpMsgBody->dpidAppServer3 = dpidServer;
+  lpMsgBody->unknown4[0] =  0x30; 
+  lpMsgBody->unknown4[1] =  0xb;
+  lpMsgBody->unknown4[2] =  0x0;
+  lpMsgBody->unknown4[3] =  0x1e090002;
+  lpMsgBody->unknown4[4] =  0x0;
+  lpMsgBody->unknown4[5] =  0x0;
+  lpMsgBody->unknown4[6] =  0x0;
+  lpMsgBody->unknown4[7] =  0x32090002;
+  lpMsgBody->unknown4[8] =  0x0;
+  lpMsgBody->unknown4[9] =  0x0;
+  lpMsgBody->unknown4[10] = 0x0;
+  lpMsgBody->unknown4[11] = 0x0;
+  lpMsgBody->unknown4[12] = 0x0;
+
+  lpMsgBody->unknown5[0] = 0x0;
+  lpMsgBody->unknown5[1] = 0x0;
+
+  /* Send the message */
+  {
+    DPSP_SENDDATA data;
+
+    data.dwFlags        = DPSEND_GUARANTEED;
+    data.idPlayerTo     = 0; /* Name server */
+    data.idPlayerFrom   = dpidServer; /* Sending from session server */
+    data.lpMessage      = lpMsg;
+    data.dwMessageSize  = dwMsgSize;
+    data.bSystemMessage = TRUE; /* Allow reply to be sent */
+    data.lpISP          = This->dp2->spData.lpISP;
+
+    lpMsg = DP_MSG_ExpectReply( This, &data, 
+                                DPMSG_WAIT_60_SECS, 
+                                DPMSGCMD_GETNAMETABLEREPLY,
+                                &lpMsg, &dwMsgSize );
+  }
+
+  /* Need to examine the data and extract the new player id */
+  if( lpMsg != NULL )
+  {
+    FIXME( "Name Table reply received: stub\n" );
+  }
+
+  return hr;
+}
+
+/* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does
+ * not seem to offer any way of uniquely differentiating between replies of the same type
+ * relative to the request sent. There is an implicit assumption that there will be no
+ * ordering issues on sends and receives from the opposite machine. No wonder MS is not
+ * a networking company.
+ */
+static
+LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA lpData, 
+                           DWORD dwWaitTime, WORD wReplyCommandId,
+                           LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize )
+{
+  HRESULT                  hr;
+  HANDLE                   hMsgReceipt;
+  DP_MSG_REPLY_STRUCT_LIST replyStructList;
+  DWORD                    dwWaitReturn;
+ 
+  /* Setup for receipt */
+  hMsgReceipt = DP_MSG_BuildAndLinkReplyStruct( This, &replyStructList, 
+                                                wReplyCommandId );
+
+  TRACE( "Sending msg and expecting cmd %u in reply within %lu ticks\n", 
+         wReplyCommandId, dwWaitTime );
+  hr = (*This->dp2->spData.lpCB->Send)( lpData );
 
   if( FAILED(hr) )
   {
-      ERR( "Request for open stream send failed: %s\n",
-           DPLAYX_HresultToString( hr ) );
+    ERR( "Request for new playerID send failed: %s\n",
+         DPLAYX_HresultToString( hr ) );
+    return NULL;
   }
 
-  /* FIXME: hack to give some time for channel to open */
-  SleepEx( 1000 /* 1 sec */, FALSE );
+  dwWaitReturn = WaitForSingleObject( hMsgReceipt, dwWaitTime );
+  if( dwWaitReturn != WAIT_OBJECT_0 )
+  {
+    ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
+    return NULL;
+  }
 
-  return hr;
+  /* Clean Up */
+  return DP_MSG_CleanReplyStruct( &replyStructList, lplpReplyMsg, lpdwMsgBodySize );
 }
+
+/* Determine if there is a matching request for this incomming message and then copy
+ * all important data. It is quite silly to have to copy the message, but the documents
+ * indicate that a copy is taken. Silly really.
+ */
+void DP_MSG_ReplyReceived( IDirectPlay2AImpl* This, WORD wCommandId, 
+                           LPCVOID lpcMsgBody, DWORD dwMsgBodySize )
+{
+  LPDP_MSG_REPLY_STRUCT_LIST lpReplyList;
+
+#if 0
+  if( wCommandId == DPMSGCMD_FORWARDADDPLAYER )
+  {
+    DebugBreak();
+  }
+#endif
+
+  /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to 
+   * avoid problems.
+   */
+  EnterCriticalSection( &This->unk->DP_lock );
+    DPQ_REMOVE_ENTRY( This->dp2->replysExpected, replysExpected, replyExpected.wExpectedReply,\
+                     ==, wCommandId, lpReplyList );
+  LeaveCriticalSection( &This->unk->DP_lock );  
+
+  if( lpReplyList != NULL )
+  {
+    lpReplyList->replyExpected.dwMsgBodySize = dwMsgBodySize; 
+    lpReplyList->replyExpected.lpReplyMsg = HeapAlloc( GetProcessHeap(),
+                                                       HEAP_ZERO_MEMORY,
+                                                       dwMsgBodySize );
+    CopyMemory( lpReplyList->replyExpected.lpReplyMsg, 
+                lpcMsgBody, dwMsgBodySize );
+
+    /* Signal the thread which sent the message that it has a reply */
+    SetEvent( lpReplyList->replyExpected.hReceipt );
+  }
+  else
+  {
+    ERR( "No receipt event set - only expecting in reply mode\n" );
+    DebugBreak();
+  }
+ 
+}
+
+void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId,
+                           LPCVOID lpMsgBody, DWORD dwMsgBodySize )
+{
+  LPCDPMSG_FORWARDADDPLAYERNACK lpcErrorMsg;
+
+  lpcErrorMsg = (LPCDPMSG_FORWARDADDPLAYERNACK)lpMsgBody;
+
+  ERR( "Received error message %u. Error is %s\n", 
+       wCommandId, DPLAYX_HresultToString( lpcErrorMsg->errorCode) );
+  DebugBreak();
+}
+
diff --git a/dlls/dplayx/dplayx_messages.h b/dlls/dplayx/dplayx_messages.h
index c1812d6..6c0dd61 100644
--- a/dlls/dplayx/dplayx_messages.h
+++ b/dlls/dplayx/dplayx_messages.h
@@ -11,6 +11,20 @@
 DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart, 
                                          HANDLE hDeath, HANDLE hConnRead );
 
+HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
+                                    LPDPID lpdipidAllocatedId );
+HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer );
+
+void DP_MSG_ReplyReceived( IDirectPlay2AImpl* This, WORD wCommandId, 
+                           LPCVOID lpMsgBody, DWORD dwMsgBodySize );
+void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId,
+                           LPCVOID lpMsgBody, DWORD dwMsgBodySize );
+
+/* Timings -> 1000 ticks/sec */
+#define DPMSG_WAIT_5_SECS   5000
+#define DPMSG_WAIT_30_SECS 30000
+#define DPMSG_WAIT_60_SECS 60000
+#define DPMSG_DEFAULT_WAIT_TIME DPMSG_WAIT_30_SECS
 
 /* Message types etc. */
 #include "pshpack1.h"
@@ -18,12 +32,12 @@
 /* Non provided messages for DPLAY - guess work which may be wrong :( */
 #define DPMSGCMD_ENUMSESSIONSREPLY    1
 #define DPMSGCMD_ENUMSESSIONSREQUEST  2
-
+#define DPMSGCMD_GETNAMETABLEREPLY    3  /* Contains all existing players in session */
 
 #define DPMSGCMD_REQUESTNEWPLAYERID   5
 
 #define DPMSGCMD_NEWPLAYERIDREPLY     7
-#define DPMSGCMD_CREATESESSION        8  
+#define DPMSGCMD_CREATESESSION        8 /* Might be a create nameserver or new player msg */ 
 #define DPMSGCMD_CREATENEWPLAYER      9
 #define DPMSGCMD_SYSTEMMESSAGE        10 
 #define DPMSGCMD_DELETEPLAYER         11
@@ -31,9 +45,9 @@
 
 #define DPMSGCMD_ENUMGROUPS           17
 
-#define DPMSGCMD_GETNAMETABLE         19
+#define DPMSGCMD_FORWARDADDPLAYER     19
 
-#define DPMSGCMD_GETNAMETABLEREPLY    29
+#define DPMSGCMD_FORWARDADDPLAYERNACK 36
 
 /* This is what DP 6 defines it as. Don't know what it means. All messages
  * defined below are DPMSGVER_DP6.
@@ -45,9 +59,8 @@
 
 /* All messages sent from the system are sent with this at the beginning of
  * the message.
+ * Size is 8 bytes
  */
-
-/* Size is 8 bytes */
 typedef struct tagDPMSG_SENDENVELOPE
 {
   DWORD dwMagic;
@@ -56,6 +69,9 @@
 } DPMSG_SENDENVELOPE, *LPDPMSG_SENDENVELOPE;
 typedef const DPMSG_SENDENVELOPE* LPCDPMSG_SENDENVELOPE;
 
+/* System messages exchanged between players seems to have this
+ * payload envelope on top of the basic envelope 
+ */
 typedef struct tagDPMSG_SYSMSGENVELOPE
 {
   DWORD dwPlayerFrom;
@@ -63,7 +79,7 @@
 } DPMSG_SYSMSGENVELOPE, *LPDPMSG_SYSMSGENVELOPE;
 typedef const DPMSG_SYSMSGENVELOPE* LPCDPMSG_SYSMSGENVELOPE;
 
-
+/* Reply sent in response to an enumsession request */
 typedef struct tagDPMSG_ENUMSESSIONSREPLY
 {
   DPMSG_SENDENVELOPE envelope;
@@ -93,13 +109,14 @@
 } DPMSG_ENUMSESSIONSREPLY, *LPDPMSG_ENUMSESSIONSREPLY;
 typedef const DPMSG_ENUMSESSIONSREPLY* LPCDPMSG_ENUMSESSIONSREPLY;
 
+/* Msg sent to find out what sessions are available */
 typedef struct tagDPMSG_ENUMSESSIONSREQUEST
 {
   DPMSG_SENDENVELOPE envelope;
 
   GUID  guidApplication;
 
-  DWORD dwPasswordSize; /* A Guess. This is normally 0x00000000. */
+  DWORD dwPasswordSize; /* A Guess. This is 0x00000000. */
                         /* This might be the name server DPID which
                            is needed for the reply */
 
@@ -131,24 +148,50 @@
   DPMSG_SENDENVELOPE envelope;
 
   DPID dpidNewPlayerId;
-#if 1
+
   /* Assume that this is data that is tacked on to the end of the message
    * that comes from the SP remote data stored that needs to be propagated.
    */
   BYTE unknown[36];     /* This appears to always be 0 - not sure though */
-#endif
-
 } DPMSG_NEWPLAYERIDREPLY, *LPDPMSG_NEWPLAYERIDREPLY;
 typedef const DPMSG_NEWPLAYERIDREPLY* LPCDPMSG_NEWPLAYERIDREPLY;
 
+typedef struct tagDPMSG_FORWARDADDPLAYER
+{
+  DPMSG_SENDENVELOPE envelope;
+
+  DWORD unknown; /* 0 */
+
+  DPID  dpidAppServer; /* Remote application server id */
+  DWORD unknown2[5]; /* ??? */
+#define FORWARDADDPLAYER_UNKNOWN2_INIT { 0x0, 0x1c, 0x6c, 0x50, 0x9 }
+
+  DPID  dpidAppServer2; /* Remote application server id again !? */
+  DWORD unknown3[5]; /* ??? */
+#define FORWARDADDPLAYER_UNKNOWN3_INIT { 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! */
+#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 }
+
+} DPMSG_FORWARDADDPLAYER, *LPDPMSG_FORWARDADDPLAYER;
+typedef const DPMSG_FORWARDADDPLAYER* LPCDPMSG_FORWARDADDPLAYER;
+
+/* This is an error message that can be received. Not sure if this is 
+ * specifically for a forward add player or for all errors
+ */
+typedef struct tagDPMSG_FORWARDADDPLAYERNACK
+{
+  DPMSG_SENDENVELOPE envelope;
+  HRESULT errorCode;
+} DPMSG_FORWARDADDPLAYERNACK, *LPDPMSG_FORWARDADDPLAYERNACK;
+typedef const DPMSG_FORWARDADDPLAYERNACK* LPCDPMSG_FORWARDADDPLAYERNACK;
+
 #include "poppack.h"
 
-
-HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
-                                    LPDPID lpdipidAllocatedId );
-
-/* FIXME: I don't think that this is a needed method */
-HRESULT DP_MSG_OpenStream( IDirectPlay2AImpl* This );
-
-
 #endif
diff --git a/dlls/dplayx/dplobby.c b/dlls/dplayx/dplobby.c
index 3a451fe..c1340c4 100644
--- a/dlls/dplayx/dplobby.c
+++ b/dlls/dplayx/dplobby.c
@@ -343,15 +343,15 @@
   TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
 
   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
-                       sizeof( IDirectPlayLobbyWImpl ) );
+                       sizeof( *This ) );
 
   if( *ppvObj == NULL )
   {
     return DPERR_OUTOFMEMORY;
   }
 
-  CopyMemory( *ppvObj, iface, sizeof( IDirectPlayLobbyWImpl )  );
-  (*(IDirectPlayLobbyWImpl**)ppvObj)->ulInterfaceRef = 0;
+  CopyMemory( *ppvObj, This, sizeof( *This )  );
+  (*(IDirectPlayLobbyAImpl**)ppvObj)->ulInterfaceRef = 0;
 
   if( IsEqualGUID( &IID_IDirectPlayLobby, riid ) )
   {