- More implementation
- Should be able to enumerate sessions anywhere with at least tcp/ip

diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c
index 7f9ccf0..cec6ac4 100644
--- a/dlls/dplayx/dplay.c
+++ b/dlls/dplayx/dplay.c
@@ -45,13 +45,15 @@
                              LPVOID lpData, DWORD dwDataSize );
 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
-static BOOL cbDeletePlayerFromAllGroups( DPID dpId, DWORD dwPlayerType, 
-                                         LPCDPNAME lpName, DWORD dwFlags, 
-                                         LPVOID lpContext );
+static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId, 
+                                                  DWORD dwPlayerType, 
+                                                  LPCDPNAME lpName, 
+                                                  DWORD dwFlags, 
+                                                  LPVOID lpContext );
 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
-static BOOL cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType, 
-                                   LPCDPNAME lpName, DWORD dwFlags, 
-                                   LPVOID lpContext );
+static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType, 
+                                            LPCDPNAME lpName, DWORD dwFlags, 
+                                            LPVOID lpContext );
 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
 
 /* Helper methods for player/group interfaces */
@@ -152,9 +154,21 @@
 static HRESULT WINAPI DP_IF_GetGroupParent
           ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
             BOOL bAnsi );
+static HRESULT WINAPI DP_IF_GetCaps
+          ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
+static HRESULT WINAPI DP_IF_EnumSessions
+          ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
+            LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
+            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
+static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
+    LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
+    DWORD dwFlags, LPVOID lpContext );
+
 
 
 static inline DPID DP_NextObjectId(void);
+static DPID DP_GetRemoteNextObjectId(void);
+
 
 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc, 
                                 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
@@ -309,6 +323,30 @@
     CloseHandle( This->dp2->hEnumSessionThread );
   }
 
+  /* Finish with the SP - have it shutdown */
+  if( This->dp2->spData.lpCB->ShutdownEx )
+  {
+    DPSP_SHUTDOWNDATA data;
+
+    TRACE( "Calling SP ShutdownEx\n" );
+
+    data.lpISP = This->dp2->spData.lpISP;
+
+    (*This->dp2->spData.lpCB->ShutdownEx)( &data );
+  }
+  else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
+  {
+    TRACE( "Calling obsolete SP Shutdown\n" );
+    (*This->dp2->spData.lpCB->Shutdown)();
+  }
+
+  /* Unload the SP */
+  if( This->dp2->hServiceProvider != 0 )
+  {
+    FreeLibrary( This->dp2->hServiceProvider );
+  }
+
+
 #if 0
   DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
   DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem );
@@ -574,6 +612,82 @@
   return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
 }
 
+/* *lplpReply will be non NULL iff there is something to reply */
+HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
+                          DWORD  dwMessageBodySize, LPCVOID lpMessageHeader,
+                          WORD wCommandId, WORD wVersion, 
+                          LPVOID* lplpReply, LPDWORD lpdwMsgSize )
+{
+  TRACE( "(%p)->(%p,0x%08lx,%p,%u,%u)\n",
+         This, lpMessageBody, dwMessageBodySize, lpMessageHeader, wCommandId, 
+         wVersion );
+
+  switch( wCommandId )
+  {
+    case DPMSGCMD_REQUESTNEWPLAYERID:
+    {
+#if 0
+      LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = 
+        (LPCDPMSG_REQUESTNEWPLAYERID)lpMessageBody;
+#endif
+      LPDPMSG_NEWPLAYERIDREPLY lpReply;
+
+      *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
+
+      *lplpReply = (LPDPMSG_NEWPLAYERIDREPLY)HeapAlloc( GetProcessHeap(), 
+                                                        HEAP_ZERO_MEMORY,
+                                                        *lpdwMsgSize );
+
+      FIXME( "Ignoring dwFlags in msg\n" );
+
+      /* Setup the reply */
+      lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) + 
+                                            This->dp2->spData.dwSPHeaderSize );
+
+      lpReply->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG;
+      lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY; 
+      lpReply->envelope.wVersion   = DPMSGVER_DP6; 
+
+#if 0
+      /* FIXME: Need to know the proper contents of the message! */
+      lpReply->dpidNewPlayerId = DP_NextObjectId();
+#endif
+
+      break;
+    }
+
+    case DPMSGCMD_NEWPLAYERIDREPLY:
+    {
+
+      DebugBreak(); 
+
+      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\n" );
+      }
+ 
+      break;
+    }
+
+    default:
+    {
+      FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
+      break;
+    }
+  }
+
+  return DP_OK;
+}
+
 
 static HRESULT WINAPI DP_IF_AddPlayerToGroup
           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, 
@@ -607,6 +721,7 @@
   }   
 
   /* Add the shortcut */
+  lpPList->lpPData->uRef++;
   lpNewPList->lpPData = lpPList->lpPData;
 
   /* Add the player to the list of players for this group */
@@ -623,7 +738,7 @@
     data.idGroup  = idGroup;
     data.lpISP    = This->dp2->spData.lpISP;
 
-    (This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
+    (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
   }
 
   /* Inform all other peers of the addition of player to the group. If there are
@@ -668,7 +783,7 @@
 {
   HRESULT hr = DP_OK;
 
-  FIXME("(%p)->(%u): stub\n", This, bAnsi );
+  TRACE("(%p)->(%u)\n", This, bAnsi );
 
   /* FIXME: Need to find a new host I assume (how?) */
   /* FIXME: Need to destroy all local groups */
@@ -683,38 +798,16 @@
 
     data.lpISP = This->dp2->spData.lpISP;
  
-    hr = (This->dp2->spData.lpCB->CloseEx)( &data );
+    hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
         
   }
   else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
   {
     TRACE( "Calling SP Close (obsolete interface)\n" );
 
-    hr = (This->dp2->spData.lpCB->Close)();
+    hr = (*This->dp2->spData.lpCB->Close)();
   }
 
-  /* Even if the SP close failed, we should press on... */
-
-  /* Invoke the SP callback to inform the SP we don't need it any more */
-  if( This->dp2->spData.lpCB->ShutdownEx )
-  {
-    DPSP_SHUTDOWNDATA data;
-
-    TRACE( "Calling SP ShutdownEx\n" );
-
-    data.lpISP = This->dp2->spData.lpISP;
-
-    hr = (This->dp2->spData.lpCB->ShutdownEx)( &data );
-  }
-  else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
-  {
-    TRACE( "Calling obsolete SP Shutdown\n" );
-    hr = (This->dp2->spData.lpCB->Shutdown)();
-  }
-
-  /* Unload the service provider now that we've stoped it */
-  FreeLibrary( This->dp2->hServiceProvider );
-
   return hr;
 }
 
@@ -781,6 +874,12 @@
     return;
   }
 
+  if( --(lpGList->lpGData->uRef) )
+  {
+    FIXME( "Why is this not the last reference to group?\n" );
+    DebugBreak();
+  }
+
   /* Delete player */
   DP_DeleteDPNameStruct( &lpGList->lpGData->name );
   HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
@@ -804,6 +903,11 @@
   {
     DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
   }
+  
+  if( lpGroups == NULL )
+  {
+    return NULL;
+  }
 
   return lpGroups->lpGData;
 }
@@ -831,11 +935,7 @@
     }
     else
     {
-      /* Request the id from the name server */
-      FIXME( "Request id from NS for group\n" );
-
-      /* Hack for now */
-      *lpidGroup = DP_NextObjectId();
+      *lpidGroup = DP_GetRemoteNextObjectId();
     }
   }
  
@@ -862,6 +962,9 @@
     DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
   }
 
+  /* Something is now referencing this data */
+  lpGData->uRef++;
+
   /* Set all the important stuff for the group */
   DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
 
@@ -891,7 +994,7 @@
     data.lpSPMessageHeader = lpMsgHdr;
     data.lpISP             = This->dp2->spData.lpISP;
 
-    (This->dp2->spData.lpCB->CreateGroup)( &data );
+    (*This->dp2->spData.lpCB->CreateGroup)( &data );
   }
 
   /* Inform all other peers of the creation of a new group. If there are 
@@ -989,12 +1092,7 @@
 
 }
 
-/* This function will just create the storage for the new player.
- * In the future it may want to intialize, but for the time being
- * that will be done seperately. 
- * 
- * If *lpid == DPID_UNKNOWN then assign the next available player
- */
+/* This function will just create the storage for the new player.  */
 static 
 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid, 
                               LPDPNAME lpName, DWORD dwFlags, 
@@ -1048,26 +1146,33 @@
 static void
 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
 {
-  lpPlayerList lpPlayers;
+  lpPlayerList lpPList;
 
   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
 
-  DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
+  DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
 
-  if( lpPlayers == NULL )
+  if( lpPList == NULL )
   {
     ERR( "DPID 0x%08lx not found\n", dpid );
     return;
   }
+
+  /* Verify that this is the last reference to the data */
+  if( --(lpPList->lpPData->uRef) )
+  {
+    FIXME( "Why is this not the last reference to player?\n" );
+    DebugBreak(); 
+  }
  
   /* Delete player */
-  DP_DeleteDPNameStruct( &lpPlayers->lpPData->name );
+  DP_DeleteDPNameStruct( &lpPList->lpPData->name );
 
-  CloseHandle( lpPlayers->lpPData->hEvent );
-  HeapFree( GetProcessHeap(), 0, lpPlayers->lpPData );
+  CloseHandle( lpPList->lpPData->hEvent );
+  HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
 
   /* Delete Player List object */
-  HeapFree( GetProcessHeap(), 0, lpPlayers );
+  HeapFree( GetProcessHeap(), 0, lpPList );
 }
 
 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
@@ -1236,11 +1341,13 @@
     }
     else
     {
-      /* Request the id from the name server */
-      FIXME( "Request id from NS for new player\n" );
+      HRESULT hr = DP_MSG_SendRequestPlayerId( This, dwFlags, lpidPlayer );
 
-      /* Hack for now */
-      *lpidPlayer = DP_NextObjectId();
+      if( FAILED(hr) )
+      {
+        ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
+        return hr;
+      }
     }
   }
   else
@@ -1258,9 +1365,6 @@
     return DPERR_CANTADDPLAYER;
   }
 
-  /* Update the information and send it to all players in the session */
-  DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );  
-
   /* Create the list object and link it in */
   lpPList = (lpPlayerList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                      sizeof( *lpPList ) );
@@ -1270,10 +1374,14 @@
     return DPERR_CANTADDPLAYER;
   }
 
+  lpPData->uRef = 1;
   lpPList->lpPData = lpPData;
 
+  /* Add the player to the system group */
   DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
 
+  /* Update the information and send it to all players in the session */
+  DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );  
 
   /* Let the SP know that we've created this player */
   if( This->dp2->spData.lpCB->CreatePlayer )
@@ -1301,19 +1409,9 @@
     data.lpSPMessageHeader = lpMsgHdr;
     data.lpISP             = This->dp2->spData.lpISP;
 
-    (This->dp2->spData.lpCB->CreatePlayer)( &data );
+    (*This->dp2->spData.lpCB->CreatePlayer)( &data );
   }
 
-  /* FIXME: The native version adds everything to group 0 (similar to
-   *        the player queue that we have. I think that the native
-   *        service providers rely on this fact.
-   * NOTE: The lpMsgHdr is always non NULL because there is no requirement to
-   *       broadcast this information since every node will automatically 
-   *       do it.
-   */
-  DP_IF_AddPlayerToGroup( This, NULL, DPID_NOPARENT_GROUP, 
-                          *lpidPlayer, bAnsi );
-
   /* Inform all other peers of the creation of a new player. If there are
    * no peers keep this quiet. 
    * Also, if this was a remote event, no need to rebroadcast it.
@@ -1345,7 +1443,8 @@
 }
 
 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
-          ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+          ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, 
+            HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
 
@@ -1363,7 +1462,8 @@
 }
 
 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
-          ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+          ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, 
+            HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
 
@@ -1380,6 +1480,14 @@
                            lpData, dwDataSize, dwFlags, FALSE );
 }
 
+static DPID DP_GetRemoteNextObjectId(void)
+{
+  FIXME( ":stub\n" );
+
+  /* Hack solution */
+  return DP_NextObjectId();
+}
+
 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, 
             DPID idPlayer, BOOL bAnsi )
@@ -1412,6 +1520,9 @@
     return DPERR_INVALIDPLAYER;
   }
 
+  /* One less reference */
+  lpPList->lpPData->uRef--;
+
   /* Delete the Player List element */
   HeapFree( GetProcessHeap(), 0, lpPList );
 
@@ -1426,7 +1537,7 @@
     data.idGroup  = idGroup;
     data.lpISP    = This->dp2->spData.lpISP;
 
-    hr = (This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
+    hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
   }
 
   /* Need to send a DELETEPLAYERFROMGROUP message */
@@ -1451,12 +1562,12 @@
 
 typedef struct _DPRGOPContext
 {
-  LPDIRECTPLAY3 iface;
-  BOOL          bAnsi;
-  DPID          idGroup;
+  IDirectPlay3Impl* This;
+  BOOL              bAnsi;
+  DPID              idGroup;
 } DPRGOPContext, *lpDPRGOPContext;
 
-static BOOL 
+static BOOL CALLBACK
 cbRemoveGroupOrPlayer(
     DPID            dpId,
     DWORD           dwPlayerType,
@@ -1471,8 +1582,8 @@
 
   if( dwPlayerType == DPPLAYERTYPE_GROUP )
   {
-    if( FAILED( IDirectPlayX_DeleteGroupFromGroup( lpCtxt->iface, 
-                                                   lpCtxt->idGroup, dpId ) 
+    if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup, 
+                                            dpId ) 
               ) 
       )
     {
@@ -1482,8 +1593,9 @@
   }
   else
   {
-    if( FAILED( IDirectPlayX_DeletePlayerFromGroup( lpCtxt->iface, 
-                                                    lpCtxt->idGroup, dpId )
+    if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This, 
+                                             NULL, lpCtxt->idGroup, 
+                                             dpId, lpCtxt->bAnsi )
               )
       )
     {
@@ -1510,27 +1622,28 @@
     return DPERR_INVALIDPLAYER; /* yes player */
   }
 
-  context.iface   = (LPDIRECTPLAY3)This;
+  context.This    = (IDirectPlay3Impl*)This;
   context.bAnsi   = bAnsi;
   context.idGroup = idGroup;
 
-  /* Remove all links to groups that this group has since this is dp3 */
-  IDirectPlayX_EnumGroupsInGroup( (LPDIRECTPLAY3A)This, idGroup, NULL, 
-                                  cbRemoveGroupOrPlayer, (LPVOID)&context, 0 );
-
-  /* FIXME: Is it allowed to delete a sub group with a parent? Must be */
-  if( lpGData->parent != DPID_SYSTEM_GROUP )
-  {
-      IDirectPlayX_DeleteGroupFromGroup( (LPDIRECTPLAY3A)This, 
-                                         lpGData->parent, 
-                                         idGroup ); 
-  } 
-  
   /* Remove all players that this group has */
-  IDirectPlayX_EnumGroupPlayers( (LPDIRECTPLAY3A)This, idGroup, NULL, 
-                                 cbRemoveGroupOrPlayer, (LPVOID)&context, 0 );
+  DP_IF_EnumGroupPlayers( This, idGroup, NULL, 
+                          cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
 
-  /* Now delete this group data and list */
+  /* Remove all links to groups that this group has since this is dp3 */
+  DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL, 
+                           cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
+
+  /* Remove this group from the parent group - if it has one */
+  if( ( idGroup != DPID_SYSTEM_GROUP ) &&
+      ( lpGData->parent != DPID_SYSTEM_GROUP )
+    )
+  {
+    DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent, 
+                                idGroup ); 
+  }
+  
+  /* Now delete this group data and list from the system group */
   DP_DeleteGroup( This, idGroup ); 
 
   /* Let the SP know that we've destroyed this group */
@@ -1544,7 +1657,7 @@
     data.dwFlags = 0; 
     data.lpISP   = This->dp2->spData.lpISP;
 
-    (This->dp2->spData.lpCB->DeleteGroup)( &data );
+    (*This->dp2->spData.lpCB->DeleteGroup)( &data );
   }
 
   FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
@@ -1568,8 +1681,9 @@
 
 typedef struct _DPFAGContext
 {
-  LPDIRECTPLAY2 iface;
-  DPID idPlayer;
+  IDirectPlay2Impl* This;
+  DPID              idPlayer;
+  BOOL              bAnsi;
 } DPFAGContext, *lpDPFAGContext;
 
 static HRESULT WINAPI DP_IF_DestroyPlayer
@@ -1587,15 +1701,16 @@
 
   /* FIXME: If the player is remote, we must be the host to delete this */
 
-  cbContext.iface = (LPDIRECTPLAY2)This;
+  cbContext.This     = This;
   cbContext.idPlayer = idPlayer;
+  cbContext.bAnsi    = bAnsi;
 
   /* Find each group and call DeletePlayerFromGroup if the player is a
      member of the group */
-  IDirectPlayX_EnumGroups( (LPDIRECTPLAY2)This, NULL, cbDeletePlayerFromAllGroups,
-                           (LPVOID)&cbContext, DPENUMGROUPS_ALL);
+  DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
+                    (LPVOID)&cbContext, DPENUMGROUPS_ALL, bAnsi );
 
-  /* Now delete player and player list */
+  /* Now delete player and player list from the sys group */
   DP_DeletePlayer( This, idPlayer );
 
   /* Let the SP know that we've destroyed this group */
@@ -1609,7 +1724,7 @@
     data.dwFlags = 0; 
     data.lpISP   = This->dp2->spData.lpISP;
 
-    (This->dp2->spData.lpCB->DeletePlayer)( &data );
+    (*This->dp2->spData.lpCB->DeletePlayer)( &data );
   }
 
   FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
@@ -1617,7 +1732,7 @@
   return DP_OK;
 }
 
-static BOOL
+static BOOL CALLBACK
 cbDeletePlayerFromAllGroups(
     DPID            dpId,
     DWORD           dwPlayerType,
@@ -1629,13 +1744,18 @@
 
   if( dwPlayerType == DPPLAYERTYPE_GROUP )
   {
-    IDirectPlayX_DeletePlayerFromGroup( lpCtxt->iface, lpCtxt->idPlayer, dpId );
+    DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
+                                 lpCtxt->bAnsi );
 
-    /* Enumerate all groups in this group - yes this is pseudo recursive */
-    IDirectPlayX_EnumGroupsInGroup( (LPDIRECTPLAY3A)lpCtxt->iface, /*FIXME*/
-                                    dpId, NULL, 
-                                    cbDeletePlayerFromAllGroups, 
-                                    lpContext, DPENUMGROUPS_ALL );
+    /* Enumerate all groups in this group since this will normally only
+     * be called for top level groups
+     */
+    DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
+                             dpId, NULL,
+                             cbDeletePlayerFromAllGroups,
+                             (LPVOID)lpContext, DPENUMGROUPS_ALL, 
+                             lpCtxt->bAnsi );
+
   }
   else
   {
@@ -1806,10 +1926,11 @@
 /* This function should call the registered callback function that the user
    passed into EnumSessions for each entry available.
  */
-static void DP_InvokeEnumSessionCallbacksA( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
-                                     LPVOID lpNSInfo,
-                                     DWORD dwTimeout,
-                                     LPVOID lpContext )
+static void DP_InvokeEnumSessionCallbacks
+       ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
+         LPVOID lpNSInfo,
+         DWORD dwTimeout,
+         LPVOID lpContext )
 {
   LPDPSESSIONDESC2 lpSessionDesc;
 
@@ -1832,33 +1953,6 @@
   lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
 }
 
-static void DP_InvokeEnumSessionCallbacksW( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
-                                     LPVOID lpNSInfo,
-                                     DWORD dwTimeout,
-                                     LPVOID lpContext )
-{
-  LPDPSESSIONDESC2 lpSessionDesc;
-
-  FIXME( ": not checking for conditions\n" );
-
-  NS_ResetSessionEnumeration( lpNSInfo );
-
-  /* Enumerate all sessions */
-  /* FIXME: Need to indicate UNICODE */
-  while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
-  {
-    TRACE( "EnumSessionsCallback2 invoked\n" );
-    if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
-    {
-      return;
-    }
-  }
-
-  /* Invoke one last time to indicate that there is no more to come */
-  lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
-  
-}
-
 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
 {
   EnumSessionAsyncCallbackData* data = (EnumSessionAsyncCallbackData*)lpContext;
@@ -1869,9 +1963,7 @@
 
   for( ;; )
   {
-    NS_SendSessionRequestBroadcast( &data->requestGuid,
-                                    data->dwEnumSessionFlags,
-                                    data->lpSpData );
+    HRESULT hr;
 
     /* Sleep up to dwTimeout waiting for request to terminate thread */
     if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
@@ -1879,6 +1971,18 @@
       TRACE( "Thread terminating on terminate request\n" );
       break;
     }
+
+    /* Now resend the enum request */
+    hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
+                                         data->dwEnumSessionFlags,
+                                         data->lpSpData );
+
+    if( FAILED(hr) )
+    {
+      ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
+      /* FIXME: Should we kill this thread? How to inform the main thread? */
+    }
+
   }
 
   TRACE( "Thread terminating\n" );
@@ -1887,6 +1991,13 @@
   CloseHandle( hSuicideRequest );
   HeapFree( GetProcessHeap(), 0, lpContext );
 
+  /* FIXME: Need to have some notification to main app thread that this is
+   *        dead. It would serve two purposes. 1) allow sync on termination
+   *        so that we don't actually send something to ourselves when we
+   *        become name server (race condition) and 2) so that if we die
+   *        abnormally something else will be able to tell.
+   */
+
   return 1;
 }
 
@@ -1908,18 +2019,16 @@
   }
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
-          ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, 
+static HRESULT WINAPI DP_IF_EnumSessions
+          ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, 
             LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
-            LPVOID lpContext, DWORD dwFlags )
+            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
 {
   HRESULT hr = DP_OK;
-  ICOM_THIS(IDirectPlay2Impl,iface);
 
-  /* FIXME: Combine ANSI and UNICODE versions */
-
-  TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx)\n", 
-         This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags );
+  TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx,%u)\n", 
+         This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
+         bAnsi );
 
   /* Can't enumerate if the interface is already open */
   if( This->dp2->bConnectionOpen )
@@ -1933,7 +2042,7 @@
     DPCAPS spCaps;
     spCaps.dwSize = sizeof( spCaps );
 
-    IDirectPlayX_GetCaps( iface, &spCaps, 0 );
+    DP_IF_GetCaps( This, &spCaps, 0 );
     dwTimeout = spCaps.dwTimeout;
 
     /* FIXME: If it's still 0, we need to provide the IP default */
@@ -1949,48 +2058,57 @@
   if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
   {
     /* Enumerate everything presently in the local session cache */
-    DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, 
-                                    This->dp2->lpNameServerData, dwTimeout, 
-                                    lpContext );
+    DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2, 
+                                   This->dp2->lpNameServerData, dwTimeout, 
+                                   lpContext );
 
 
     /* See if we've already created a thread to service this interface */
     if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
     {
       DWORD dwThreadId;
-      EnumSessionAsyncCallbackData* lpData 
-        = (EnumSessionAsyncCallbackData*)HeapAlloc( GetProcessHeap(),
-                                                    HEAP_ZERO_MEMORY,
-                                                    sizeof( *lpData ) );
-      /* FIXME: need to kill the thread on object deletion */
-      lpData->lpSpData  = &This->dp2->spData;
-      CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
-      lpData->dwEnumSessionFlags = dwFlags;
-      lpData->dwTimeout = dwTimeout;
 
-      This->dp2->hKillEnumSessionThreadEvent = 
-        CreateEventA( NULL, TRUE, FALSE, NULL );
+      /* Send the first enum request inline since the user may cancel a dialog
+       * if one is presented. Also, may also have a connecting return code.
+       */
+      hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
+                                           dwFlags, &This->dp2->spData );
 
-      if( !DuplicateHandle( GetCurrentProcess(), 
-                            This->dp2->hKillEnumSessionThreadEvent,
-                            GetCurrentProcess(),
-                            &lpData->hSuicideRequest,
-                            0, FALSE, DUPLICATE_SAME_ACCESS )
-        )
+      if( !FAILED(hr) )
       {
-        ERR( "Can't duplicate thread killing handle\n" );
+        EnumSessionAsyncCallbackData* lpData 
+          = (EnumSessionAsyncCallbackData*)HeapAlloc( GetProcessHeap(),
+                                                      HEAP_ZERO_MEMORY,
+                                                       sizeof( *lpData ) );
+        /* FIXME: need to kill the thread on object deletion */
+        lpData->lpSpData  = &This->dp2->spData;
+        CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
+        lpData->dwEnumSessionFlags = dwFlags;
+        lpData->dwTimeout = dwTimeout;
+  
+        This->dp2->hKillEnumSessionThreadEvent = 
+          CreateEventA( NULL, TRUE, FALSE, NULL );
+  
+        if( !DuplicateHandle( GetCurrentProcess(), 
+                              This->dp2->hKillEnumSessionThreadEvent,
+                              GetCurrentProcess(),
+                              &lpData->hSuicideRequest,
+                              0, FALSE, DUPLICATE_SAME_ACCESS )
+          )
+        {
+          ERR( "Can't duplicate thread killing handle\n" );
+        }
+  
+        TRACE( ": creating EnumSessionsRequest thread\n" );
+  
+        This->dp2->hEnumSessionThread = CreateThread( NULL,
+                                                      0,
+                                                      DP_EnumSessionsSendAsyncRequestThread,
+                                                      lpData,
+                                                      0,
+                                                      &dwThreadId );
       }
-    
-      TRACE( ": creating EnumSessionsRequest thread\n" );
-
-      This->dp2->hEnumSessionThread = CreateThread( NULL,
-                                                    0,
-                                                    DP_EnumSessionsSendAsyncRequestThread,
-                                                    lpData,
-                                                    0,
-                                                    &dwThreadId );
-    }
-
+    } 
   }
   else
   {
@@ -2005,116 +2123,32 @@
 
     SleepEx( dwTimeout, FALSE );
 
-    DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, 
-                                    This->dp2->lpNameServerData, dwTimeout, lpContext );
+    DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2, 
+                                   This->dp2->lpNameServerData, dwTimeout, 
+                                   lpContext );
   }
 
   return hr;
 }
 
+static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
+          ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, 
+            LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
+            LPVOID lpContext, DWORD dwFlags )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
+                             lpContext, dwFlags, TRUE );
+}
+
 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
           ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, 
             LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
             LPVOID lpContext, DWORD dwFlags )
 {
-  HRESULT hr = DP_OK;
   ICOM_THIS(IDirectPlay2Impl,iface);
-
-  TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx)\n", 
-         This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags );
-
-  /* Can't enumerate if the interface is already open */
-  if( This->dp2->bConnectionOpen )
-  {
-    return DPERR_GENERIC;
-  }
-
-  /* Use the service provider default? */
-  if( dwTimeout == 0 )
-  {
-    DPCAPS spCaps;
-    spCaps.dwSize = sizeof( spCaps );
-
-    IDirectPlayX_GetCaps( iface, &spCaps, 0 );
-    dwTimeout = spCaps.dwTimeout;
-  }
-
-  /* FIXME: Interface locking ... */
-
-  if( dwFlags & DPENUMSESSIONS_STOPASYNC )
-  {
-    DP_KillEnumSessionThread( This );
-
-    return hr;
-  }
-
-  /* FIXME: Interface locking sucks in this method */
-
-  if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
-  {
-    /* Enumerate everything presently in the local session cache */
-    DP_InvokeEnumSessionCallbacksW( lpEnumSessionsCallback2, 
-                                    This->dp2->lpNameServerData, 
-                                    dwTimeout, lpContext );
-
-    /* See if we've already created a thread to service this interface */
-    if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
-    {
-      DWORD dwThreadId;
-
-      EnumSessionAsyncCallbackData* lpData
-        = (EnumSessionAsyncCallbackData*)HeapAlloc( GetProcessHeap(),
-                                                    HEAP_ZERO_MEMORY,
-                                                    sizeof( *lpData ) );
-      /* FIXME: need to kill the thread on object deletion */
-      lpData->lpSpData  = &This->dp2->spData;
-      CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
-      lpData->dwEnumSessionFlags = dwFlags;
-      lpData->dwTimeout = dwTimeout;
-
-      This->dp2->hKillEnumSessionThreadEvent =
-        CreateEventA( NULL, TRUE, FALSE, NULL );
-
-      if( !DuplicateHandle( GetCurrentProcess(),
-                            This->dp2->hKillEnumSessionThreadEvent,
-                            GetCurrentProcess(),
-                            &lpData->hSuicideRequest,
-                            0, FALSE, DUPLICATE_SAME_ACCESS )
-        )
-      {
-        ERR( "Can't duplicate thread killing handle\n" );
-      }
-
-
-      TRACE( ": creating EnumSessionsRequest thread\n" );
-
-      This->dp2->hEnumSessionThread = CreateThread( NULL,
-                                                    0,
-                                                    DP_EnumSessionsSendAsyncRequestThread,
-                                                    lpData,
-                                                    0,
-                                                    &dwThreadId );
-    }
-
-  }
-  else
-  {
-    /* Invalidate the session cache for the interface */
-    NS_InvalidateSessionCache( This->dp2->lpNameServerData );
-
-    /* Send the broadcast for session enumeration */
-    hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
-                                         dwFlags,
-                                         &This->dp2->spData );
-
-    SleepEx( dwTimeout, FALSE );
-
-    DP_InvokeEnumSessionCallbacksW( lpEnumSessionsCallback2, 
-                                    This->dp2->lpNameServerData, 
-                                    dwTimeout, lpContext );
-  }
-
-  return hr;
+  return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
+                             lpContext, dwFlags, FALSE );
 }
 
 static HRESULT WINAPI DP_IF_GetPlayerCaps
@@ -2131,22 +2165,27 @@
   data.lpCaps   = lpDPCaps;
   data.lpISP    = This->dp2->spData.lpISP;
 
-  return (This->dp2->spData.lpCB->GetCaps)( &data );
+  return (*This->dp2->spData.lpCB->GetCaps)( &data );
 }
 
+static HRESULT WINAPI DP_IF_GetCaps
+          ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
+{
+  return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
+}
 
 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
           ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
+  return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
 }
 
 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
           ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
+  return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
 }
 
 static HRESULT WINAPI DP_IF_GetGroupData
@@ -2605,11 +2644,16 @@
     data.dwOpenFlags       = dwFlags;
     data.dwSessionFlags    = This->dp2->lpSessionDesc->dwFlags;
 
-    hr = (This->dp2->spData.lpCB->Open)(&data);
+    hr = (*This->dp2->spData.lpCB->Open)(&data);
+    if( FAILED( hr ) )
+    {
+      ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );  
+      return hr;
+    }
   }
- 
+
   {
-    /* FIXME: DPLAY creates this after the name server... */
+    /* Create the system group of which everything is a part of */
     DPID systemGroup = DPID_SYSTEM_GROUP;
 
     hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
@@ -2630,7 +2674,8 @@
      *        message is directed to.
      */
     hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL, 
-                             0, DPPLAYER_SERVERPLAYER, bAnsi );
+                             0, 
+                             DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
   }
   else if( dwFlags & DPOPEN_CREATE )
   {
@@ -3138,6 +3183,7 @@
   }  
 
   /* Add the shortcut */
+  lpGData->uRef++;
   lpNewGList->lpGData = lpGData;
 
   /* Add the player to the list of players for this group */
@@ -3191,6 +3237,9 @@
   {
     return DPERR_CANTADDPLAYER; /* yes player not group */
   }
+
+  /* Something else is referencing this data */
+  lpGData->uRef++;
   
   DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
 
@@ -3220,7 +3269,7 @@
     data.lpSPMessageHeader = lpMsgHdr;
     data.lpISP             = This->dp2->spData.lpISP;
 
-    (This->dp2->spData.lpCB->CreateGroup)( &data );
+    (*This->dp2->spData.lpCB->CreateGroup)( &data );
   }
 
   /* Inform all other peers of the creation of a new group. If there are 
@@ -3300,6 +3349,9 @@
     return DPERR_INVALIDGROUP;
   }
 
+  /* Decrement the ref count */
+  lpGList->lpGData->uRef--;
+
   /* Free up the list item */
   HeapFree( GetProcessHeap(), 0, lpGList ); 
 
@@ -3869,9 +3921,6 @@
     return DPERR_UNAVAILABLE;
   }  
 
-  /* NOTE: This will crash until I know what parameters/interface this has */
-  /* The first parameter is a pointer to memory which is written to... */
-
   TRACE( "Calling SPInit\n" );
   hr = (*SPInit)( &This->dp2->spData );
 
@@ -4136,7 +4185,7 @@
   {
     bValidDestination = TRUE;
 
-    /* Have the servie provider send this message */
+    /* Have the service provider send this message */
     /* FIXME: Could optimize for local interface sends */
     return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
                          dwTimeout, lpContext, lpdwMsgID );
@@ -4161,6 +4210,21 @@
     {
       FIXME( "Send to all players using EnumPlayersInGroup\n" );
     }
+
+#if 0
+    if( bExpectReply )
+    {
+      DWORD dwWaitReturn;
+
+      This->dp2->hReplyEvent = CreateEventA( NULL, FALSE, FALSE, NULL );
+
+      dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
+      if( dwWaitReturn != WAIT_OBJECT_0 )
+      {
+        ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
+      }
+    }
+#endif
   }
 
   if( !bValidDestination )
@@ -4202,38 +4266,18 @@
 {
   LPDPMSG lpMElem;
 
-  FIXME( ": stub - wont work for multi process\n" );
+  FIXME( ": stub\n" );
 
-  /* FIXME: Need to send the passed message inside another message type
-   *        I think. System message - but what is the format? 
-   */
+  /* FIXME: This queuing should only be for async messages */
 
-  /* OK. Let's run a nasty hack to bypass the fact that we don't yet know
-     how to initialize the service provider. The hack will place the message
-     to be sent automatically into the send queue. There will
-     be nothing put into the send queue. In reality we should be calling
-     the service provider and only putting things into the send queue if
-     the service provider can't immediately accept/send it. 
-     NOTE: Two hacks are provided. The first is only for a single process,
-           the second is a start towards a allowing sharing across the whole
-           computer (it requires some way of signalling that there's a message
-           available).
-   */
-
-#ifdef SP_MULTIPROCESS_SEND_HACK
-  lpMElem = (LPDPMSG)DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
-                                           sizeof( *lpMElem ) );
-  lpMElem->msg = (DPMSG_GENERIC*)DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
-                                                       dwDataSize );
-#else
   lpMElem = (LPDPMSG)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                sizeof( *lpMElem ) );
   lpMElem->msg = (DPMSG_GENERIC*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
                                             dwDataSize );
-#endif
 
   CopyMemory( lpMElem->msg, lpData, dwDataSize );
 
+  /* FIXME: Need to queue based on priority */
   DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs ); 
    
   return DP_OK;
@@ -4266,7 +4310,7 @@
     data.lpdwNumMsgs  = lpdwNumMsgs;
     data.lpdwNumBytes = lpdwNumBytes;
   
-    hr = (This->dp2->spData.lpCB->GetMessageQueue)( &data );
+    hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
   }
   else
   {
@@ -4318,7 +4362,7 @@
     data.dwMinPriority  = dwMinPriority;
     data.dwMaxPriority  = dwMaxPriority;
 
-    hr = (This->dp2->spData.lpCB->Cancel)( &data );
+    hr = (*This->dp2->spData.lpCB->Cancel)( &data );
   }
   else
   {
@@ -4900,7 +4944,7 @@
 } CreateEnumData, *lpCreateEnumData;
 
 /* Find and copy the matching connection for the SP guid */
-BOOL CALLBACK cbDPCreateEnumConnections( 
+static BOOL CALLBACK cbDPCreateEnumConnections( 
     LPCGUID     lpguidSP,
     LPVOID      lpConnection,
     DWORD       dwConnectionSize,
diff --git a/dlls/dplayx/dplay_global.h b/dlls/dplayx/dplay_global.h
index 8547568..0cfc5f5 100644
--- a/dlls/dplayx/dplay_global.h
+++ b/dlls/dplayx/dplay_global.h
@@ -43,6 +43,8 @@
   DPNAME name;
   HANDLE hEvent;
 
+  ULONG  uRef;  /* What is the reference count on this data? */
+
   /* View of local data */
   LPVOID lpLocalData;
   DWORD  dwLocalDataSize;
@@ -68,6 +70,8 @@
   /* Internal information */
   DPID parent; /* If parent == 0 it's a top level group */
 
+  ULONG uRef; /* Reference count */
+
   DPQ_HEAD(GroupList)  groups;  /* A group has [0..n] groups */
   DPQ_HEAD(PlayerList) players; /* A group has [0..n] players */
 
@@ -117,12 +121,7 @@
 
   BOOL bHostInterface; /* Did this interface create the session */
 
-#if 0
-  DPQ_HEAD(PlayerList) players; /* All players w/ interface */
-  DPQ_HEAD(GroupList)  groups;  /* All main groups w/ interface */
-#else 
   lpGroupData lpSysGroup; /* System group with _everything_ in it */
-#endif
 
   LPDPSESSIONDESC2 lpSessionDesc;
 
@@ -137,6 +136,11 @@
   HMODULE hServiceProvider;
 
   BOOL bConnectionInitialized;
+
+
+  /* proof of concept for message reception */
+  HANDLE hMsgReceipt;
+  LPVOID lpMsgReceived;
 } DirectPlay2Data;
 
 typedef struct tagDirectPlay3Data
@@ -182,4 +186,11 @@
 extern ICOM_VTABLE(IDirectPlay3) directPlay3WVT;
 extern ICOM_VTABLE(IDirectPlay4) directPlay4WVT;
 
+
+HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
+                          DWORD  dwMessageBodySize, LPCVOID lpMessageHeader,
+                          WORD wCommandId, WORD wVersion, 
+                          LPVOID* lplpReply, LPDWORD lpdwMsgSize );
+
+
 #endif /* __WINE_DPLAY_GLOBAL_INCLUDED */
diff --git a/dlls/dplayx/dplaysp.c b/dlls/dplayx/dplaysp.c
index 98962de..1148dc8 100644
--- a/dlls/dplayx/dplaysp.c
+++ b/dlls/dplayx/dplaysp.c
@@ -384,6 +384,8 @@
 {
   LPDPMSG_SENDENVELOPE lpMsg = (LPDPMSG_SENDENVELOPE)lpMessageBody;
   HRESULT hr = DPERR_GENERIC;
+  WORD wCommandId;
+  WORD wVersion;
 
   ICOM_THIS(IDirectPlaySPImpl,iface);
 
@@ -391,16 +393,20 @@
   FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n", 
          This, lpMessageBody, dwMessageBodySize, lpMessageHeader );
 
+  wCommandId = lpMsg->wCommandId;
+  wVersion   = lpMsg->wVersion;
+
   TRACE( "Incomming message has envelope of 0x%08lx, %u, %u\n", 
-         lpMsg->dwMagic, lpMsg->wCommandId, lpMsg->wVersion );
+         lpMsg->dwMagic, wCommandId, wVersion );
 
   if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG )
   {
-    FIXME( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic );
+    ERR( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic );
   }
 
   switch( lpMsg->wCommandId )
   {
+    /* Name server needs to handle this request */
     case DPMSGCMD_ENUMSESSIONSREQUEST:
     {
       DPSP_REPLYDATA data;
@@ -421,6 +427,7 @@
       break;
     }
 
+    /* Name server needs to handle this request */
     case DPMSGCMD_ENUMSESSIONSREPLY:
     {
       NS_SetRemoteComputerAsNameServer( lpMessageHeader, 
@@ -432,8 +439,43 @@
 
       break;
     }
+
+    case DPMSGCMD_NEWPLAYERIDREPLY:
+    case DPMSGCMD_REQUESTNEWPLAYERID:
+    {
+      DPSP_REPLYDATA data;
+      
+      data.lpMessage     = NULL;
+      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 );
+
+      /* 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;
+    }
+
     default:
-      FIXME( "Unknown Command of %u\n", lpMsg->wCommandId );
+      FIXME( "Unknown Command of %u and size 0x%08lx\n", 
+             lpMsg->wCommandId, dwMessageBodySize );
   }
 
 #if 0
@@ -443,10 +485,7 @@
   /* FIXME: Need some sort of context for this callback. Need to determine
    *        how this is actually done with the SP
    */
-  /* FIXME: Add in size checks for all messages to determine corrupt messages */  /* FIXME: Who needs to delete the message when done? */
-  /* FIXME: Does this get invoked as soon as the message arrives, or as soon
-   *        as it's removed from the queue (or peeked in queue?)
-   */
+  /* FIXME: Who needs to delete the message when done? */
   switch( lpMsg->dwType )
   {
     case DPSYS_CREATEPLAYERORGROUP:
diff --git a/dlls/dplayx/dplaysp.h b/dlls/dplayx/dplaysp.h
index c2028f0..9072e30 100644
--- a/dlls/dplayx/dplaysp.h
+++ b/dlls/dplayx/dplaysp.h
@@ -331,7 +331,7 @@
 /* This variable is exported from the DLL at ordinal 6 to be accessed by the 
  * SP directly 
  */
-extern DWORD gdwDPlaySPRefCount;
+extern __declspec(dllimport) DWORD gdwDPlaySPRefCount;
 
 #endif
 
diff --git a/dlls/dplayx/dplayx_messages.c b/dlls/dplayx/dplayx_messages.c
index bc23ef2..c4a4ac0 100644
--- a/dlls/dplayx/dplayx_messages.c
+++ b/dlls/dplayx/dplayx_messages.c
@@ -11,8 +11,11 @@
 
 #include "wingdi.h"
 #include "winuser.h"
+#include "winerror.h"
 
 #include "dplayx_messages.h"
+#include "dplay_global.h"
+#include "dplayx_global.h"
 
 DEFAULT_DEBUG_CHANNEL(dplay)
 
@@ -136,3 +139,103 @@
   return 0;
 }
 
+
+HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
+                                    LPDPID lpdpidAllocatedId )
+{
+  LPVOID                     lpMsg;
+  LPDPMSG_REQUESTNEWPLAYERID lpMsgBody;
+  DWORD                      dwMsgSize;
+  DWORD                      dwWaitReturn;
+  HRESULT                    hr = DP_OK;
+
+  FIXME( "semi stub\n" );
+
+  DebugBreak();
+
+  dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
+
+  lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
+
+  lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg + 
+                                             This->dp2->spData.dwSPHeaderSize );
+
+  lpMsgBody->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG;
+  lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID;
+  lpMsgBody->envelope.wVersion   = DPMSGVER_DP6;
+
+  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...
+   */
+  { 
+    DPSP_SENDDATA data;
+
+    data.dwFlags        = DPSEND_GUARANTEED;
+    data.idPlayerTo     = 0; /* Name server */
+    data.idPlayerFrom   = 0; /* Sending from DP */
+    data.lpMessage      = lpMsg;
+    data.dwMessageSize  = dwMsgSize;
+    data.bSystemMessage = TRUE; /* Allow reply to be sent */
+    data.lpISP          = This->dp2->spData.lpISP;
+
+    /* Setup for receipt */
+    This->dp2->hMsgReceipt = CreateEventA( NULL, FALSE, FALSE, NULL );
+ 
+    hr = (*This->dp2->spData.lpCB->Send)( &data );
+
+    if( FAILED(hr) )
+    {
+      ERR( "Request for new playerID send failed: %s\n",
+           DPLAYX_HresultToString( hr ) );
+    }
+  }
+
+  dwWaitReturn = WaitForSingleObject( This->dp2->hMsgReceipt, 30000 );
+  if( dwWaitReturn != WAIT_OBJECT_0 )
+  {
+    ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
+  }
+
+  CloseHandle( This->dp2->hMsgReceipt );
+  This->dp2->hMsgReceipt = 0;
+
+  /* Need to examine the data and extract the new player id */
+  /* I just hope that dplay doesn't return the whole new player! */
+
+  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       hr;
+  DPSP_SENDDATA data;
+
+  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;
+
+  hr = (*This->dp2->spData.lpCB->Send)( &data );
+
+  if( FAILED(hr) )
+  {
+      ERR( "Request for open stream send failed: %s\n",
+           DPLAYX_HresultToString( hr ) );
+  }
+
+  /* FIXME: hack to give some time for channel to open */
+  SleepEx( 1000 /* 1 sec */, FALSE );
+
+  return hr;
+}
diff --git a/dlls/dplayx/dplayx_messages.h b/dlls/dplayx/dplayx_messages.h
index 7c8cd07..7703435 100644
--- a/dlls/dplayx/dplayx_messages.h
+++ b/dlls/dplayx/dplayx_messages.h
@@ -6,6 +6,8 @@
 #include "dplay.h"
 #include "rpc.h" /* For GUID */
 
+#include "dplay_global.h"
+
 DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart, 
                                          HANDLE hDeath, HANDLE hConnRead );
 
@@ -27,11 +29,13 @@
 #define DPMSGCMD_CREATESESSION        8  
 #define DPMSGCMD_CREATENEWPLAYER      9
 #define DPMSGCMD_SYSTEMMESSAGE        10 
-
+#define DPMSGCMD_DELETEPLAYER         11
 #define DPMSGCMD_DELETEGROUP          12
 
 #define DPMSGCMD_ENUMGROUPS           17
 
+#define DPMSGCMD_FORWARDCREATEPLAYER  19  /* This may be a get name table req */
+
 /* This is what DP 6 defines it as. Don't know what it means. All messages
  * defined below are DPMSGVER_DP6.
  */
@@ -112,12 +116,12 @@
 } DPMSG_CREATESESSION, *LPDPMSG_CREATESESSION;
 typedef const DPMSG_CREATESESSION* LPCDPMSG_CREATESESSION;
 
-/* 28 bytes - ~18 header ~= 10 bytes msg */
+/* 12 bytes msg */
 typedef struct tagDPMSG_REQUESTNEWPLAYERID
 {
   DPMSG_SENDENVELOPE envelope;
 
-  
+  DWORD dwFlags;  /* dwFlags used for CreatePlayer */
 
 } DPMSG_REQUESTNEWPLAYERID, *LPDPMSG_REQUESTNEWPLAYERID;
 typedef const DPMSG_REQUESTNEWPLAYERID* LPCDPMSG_REQUESTNEWPLAYERID;
@@ -127,10 +131,23 @@
 {
   DPMSG_SENDENVELOPE envelope;
 
+#if 0
+  DPID dpidNewPlayerId;
+#else
+  BYTE unknown[38];
+#endif
+
 } DPMSG_NEWPLAYERIDREPLY, *LPDPMSG_NEWPLAYERIDREPLY;
 typedef const DPMSG_NEWPLAYERIDREPLY* LPCDPMSG_NEWPLAYERIDREPLY;
 
-
 #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/name_server.c b/dlls/dplayx/name_server.c
index 07a66dc..3a1ef07 100644
--- a/dlls/dplayx/name_server.c
+++ b/dlls/dplayx/name_server.c
@@ -303,7 +303,8 @@
   lpReplyData->lpMessage     = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                           lpReplyData->dwMessageSize );
 
-  rmsg = (LPDPMSG_ENUMSESSIONSREPLY)lpReplyData->lpMessage;  
+  rmsg = (LPDPMSG_ENUMSESSIONSREPLY)( (BYTE*)lpReplyData->lpMessage + 
+                                             lpDP->dp2->spData.dwSPHeaderSize);
 
   rmsg->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG; 
   rmsg->envelope.wCommandId = DPMSGCMD_ENUMSESSIONSREPLY;
@@ -323,7 +324,7 @@
     string = lpDP->dp2->lpSessionDesc->sess.lpszSessionName;
   }
 
-  lstrcpyW( (LPWSTR)rmsg+1, string );
+  lstrcpyW( (LPWSTR)(rmsg+1), string );
  
 }