- Make ref counting a little more efficient
- Correct suspended process resumption
- Don't use sys/queue.h anymore
- Properly initialize the global semaphore across processes
- Create a mapped file for shared data structures
- Change some trace messages
- Allocate dynamic shared data from the mapped file
- Rework setting and retrieving lobby settings from shared memory
- Add infrastructure for syncronization after app launch
- Small documentation update
- Include some stuff missing from header
- Start on dp and dpl message infrastructure
- Unicode versions of player/group commands added
- Combined Connect/ConnectEx and Open/SecureOpen
- More implementation

diff --git a/dlls/dplayx/Makefile.in b/dlls/dplayx/Makefile.in
index 393fb87..a48c400 100644
--- a/dlls/dplayx/Makefile.in
+++ b/dlls/dplayx/Makefile.in
@@ -6,12 +6,14 @@
 SOVERSION = 1.0
 IMPORTS   = ole32
 
-C_SRCS = dplay.c \
-         dplobby.c \
-         dpclassfactory.c \
-         dplayx_main.c \
-         dplayx_global.c \
-         name_server.c
+C_SRCS = \
+	dpclassfactory.c \
+	dplay.c \
+	dplayx_global.c \
+	dplayx_main.c \
+	dplayx_messages.c \
+	dplobby.c \
+	name_server.c
 
 @MAKE_DLL_RULES@
 
diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c
index e9bd6fa..68c2770 100644
--- a/dlls/dplayx/dplay.c
+++ b/dlls/dplayx/dplay.c
@@ -20,13 +20,14 @@
 #include "name_server.h"
 #include "dplayx_queue.h"
 
+DEFAULT_DEBUG_CHANNEL(dplay)
+
+
 /* FIXME: This stuff shouldn't really be here. It indicates a poor architectural coupling */
 #include "dplobby.h"
 extern HRESULT DPL_CreateCompoundAddress ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
                                            LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
 
-DEFAULT_DEBUG_CHANNEL(dplay)
-
 
 /*****************************************************************************
  * Predeclare the interface implementation structures
@@ -79,7 +80,7 @@
 
 struct PlayerList
 {
-  TAILQ_ENTRY(PlayerList) players;
+  DPQ_ENTRY(PlayerList) players;
 
   lpPlayerData lpPData;
 };
@@ -90,8 +91,8 @@
   /* Internal information */
   struct GroupData* parent; /* If parent == NULL it's a top level group */
 
-  TAILQ_HEAD(,GroupList)  groups;  /* A group has [0..n] groups */
-  TAILQ_HEAD(,PlayerList) players; /* A group has [0..n] players */
+  DPQ_HEAD(GroupList)  groups;  /* A group has [0..n] groups */
+  DPQ_HEAD(PlayerList) players; /* A group has [0..n] players */
 
   DPID idGroupOwner; /* ID of player who owns the group */
 
@@ -105,7 +106,7 @@
 
 struct GroupList
 {
-  TAILQ_ENTRY(GroupList) groups;
+  DPQ_ENTRY(GroupList) groups;
 
   lpGroupData lpGData;
 };
@@ -124,8 +125,8 @@
 
   BOOL bHostInterface; /* Did this interface create the session */
 
-  TAILQ_HEAD( ,PlayerList) players; /* All players w/ interface */
-  TAILQ_HEAD( ,GroupList)  groups;  /* All main groups w/ interface */
+  DPQ_HEAD(PlayerList) players; /* All players w/ interface */
+  DPQ_HEAD(GroupList)  groups;  /* All main groups w/ interface */
 } DirectPlay2Data;
 
 typedef struct tagDirectPlay3Data
@@ -173,7 +174,7 @@
 
 /* Local function prototypes */
 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
-static lpPlayerData DP_CreatePlayer( IDirectPlay2* iface, LPDPID lpid, 
+static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid, 
                                      LPDPNAME lpName, HANDLE hEvent, 
                                      BOOL bAnsi );
 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi );
@@ -197,6 +198,67 @@
                                    LPVOID lpContext );
 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
 
+/* Helper methods for player/group interfaces */
+static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
+          ( IDirectPlay2Impl* This, DPID idGroup, DPID idPlayer, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_CreatePlayer
+          ( IDirectPlay2Impl* This, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
+            HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, 
+            DWORD dwFlags, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_DestroyGroup
+          ( IDirectPlay2Impl* This, DPID idGroup, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_DestroyPlayer
+          ( IDirectPlay2Impl* This, DPID idPlayer, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_EnumGroupPlayers
+          ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
+            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_EnumGroups
+          ( IDirectPlay2Impl* This, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
+            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_EnumPlayers
+          ( IDirectPlay2Impl* This, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
+            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_GetGroupData
+          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, 
+            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_GetGroupName
+          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, 
+            LPDWORD lpdwDataSize, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_GetPlayerData
+          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
+            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_GetPlayerName
+          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
+            LPDWORD lpdwDataSize, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_SetGroupName
+          ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName, 
+            DWORD dwFlags, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_SetPlayerData
+          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, 
+            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_SetPlayerName
+          ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName, 
+            DWORD dwFlags, BOOL bAnsi );
+static HRESULT WINAPI DP_IF_AddGroupToGroup
+          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
+static HRESULT WINAPI DP_IF_CreateGroupInGroup
+          ( IDirectPlay3Impl* This, DPID idParentGroup, LPDPID lpidGroup,
+            LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
+            DWORD dwFlags );
+static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
+          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
+
+
+static HRESULT WINAPI DP_SecureOpen
+          ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
+            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials );
+
+
+
+
 
 static DWORD kludgePlayerGroupId = 1000;
 
@@ -252,8 +314,8 @@
 
   This->dp2->bHostInterface = FALSE;
 
-  TAILQ_INIT(&This->dp2->players);
-  TAILQ_INIT(&This->dp2->groups);
+  DPQ_INIT(This->dp2->players);
+  DPQ_INIT(This->dp2->groups);
 
   if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
   {
@@ -646,11 +708,7 @@
   ULONG refCount;
   ICOM_THIS(IDirectPlay3Impl,iface);
 
-  EnterCriticalSection( &This->unk->DP_lock ); 
-  {
-    refCount = ++(This->unk->ref);
-  }  
-  LeaveCriticalSection( &This->unk->DP_lock );
+  refCount = InterlockedIncrement( &This->unk->ref );
 
   TRACE("ref count incremented to %lu for %p\n", refCount, This );
 
@@ -664,11 +722,7 @@
 
   ICOM_THIS(IDirectPlay3Impl,iface);
 
-  EnterCriticalSection( &This->unk->DP_lock );
-  {
-    refCount = --(This->unk->ref);
-  }
-  LeaveCriticalSection( &This->unk->DP_lock );
+  refCount = InterlockedDecrement( &This->unk->ref );
 
   TRACE("ref count decremented to %lu for %p\n", refCount, This );
 
@@ -720,7 +774,7 @@
   lpNewPList->lpPData = lpPList->lpPData;
 
   /* Add the player to the list of players for this group */
-  TAILQ_INSERT_TAIL(&lpGList->lpGData->players,lpNewPList,players);
+  DPQ_INSERT(lpGList->lpGData->players,lpNewPList,players);
 
   /* Send a ADDPLAYERTOGROUP message */
   FIXME( "Not sending message\n" );
@@ -782,7 +836,7 @@
     return NULL;
   }
 
-  TAILQ_INSERT_TAIL(&This->dp2->groups,lpGroup,groups);
+  DPQ_INSERT(This->dp2->groups,lpGroup,groups);
 
   if( *lpid == DPID_UNKNOWN )
   {
@@ -810,7 +864,7 @@
 
   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
 
-  TAILQ_REMOVE_ENTRY( &This->dp2->groups, groups, lpGData->dpid, dpid, lpGList );
+  DPQ_REMOVE_ENTRY( This->dp2->groups, groups, lpGData->dpid, dpid, lpGList );
 
   if( lpGList == NULL )
   {
@@ -827,7 +881,6 @@
  
 }
 
-
 /* This function only finds top level groups */
 static lpGroupList DP_FindTopGroup( IDirectPlay2AImpl* This, DPID dpid )
 {
@@ -858,7 +911,7 @@
 
   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
 
-  TAILQ_FIND_ENTRY( &This->dp2->groups, groups, lpGData->dpid, dpid, lpGroups );
+  DPQ_FIND_ENTRY( This->dp2->groups, groups, lpGData->dpid, dpid, lpGroups );
 
   return lpGroups;
 }
@@ -928,10 +981,9 @@
  * If *lpid == DPID_UNKNOWN then assign the next available player
  */
 static 
-lpPlayerData DP_CreatePlayer( IDirectPlay2* iface, LPDPID lpid, 
+lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid, 
                               LPDPNAME lpName, HANDLE hEvent, BOOL bAnsi )
 {
-  ICOM_THIS(IDirectPlay2Impl,iface);
   lpPlayerList lpPlayer;
 
   TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
@@ -956,7 +1008,7 @@
   }
 
   /* Insert the player list into the master list of players */
-  TAILQ_INSERT_TAIL(&This->dp2->players,lpPlayer,players);
+  DPQ_INSERT( This->dp2->players, lpPlayer, players );
 
   if( *lpid == DPID_UNKNOWN )
   {
@@ -992,7 +1044,7 @@
 
   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
 
-  TAILQ_REMOVE_ENTRY( &This->dp2->players, players, lpPData->dpid, dpid, lpPlayers );
+  DPQ_REMOVE_ENTRY( This->dp2->players, players, lpPData->dpid, dpid, lpPlayers );
 
   if( lpPlayers == NULL )
   {
@@ -1015,7 +1067,7 @@
 
   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
 
-  TAILQ_FIND_ENTRY( &This->dp2->players, players, lpPData->dpid, dpid, lpPlayers );
+  DPQ_FIND_ENTRY( This->dp2->players, players, lpPData->dpid, dpid, lpPlayers );
 
   return lpPlayers;
 }
@@ -1105,19 +1157,21 @@
   
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer 
-( LPDIRECTPLAY2A iface, 
+static HRESULT WINAPI DP_IF_CreatePlayer 
+( IDirectPlay2Impl* This, 
   LPDPID lpidPlayer, 
   LPDPNAME lpPlayerName, 
   HANDLE hEvent, 
   LPVOID lpData, 
   DWORD dwDataSize, 
-  DWORD dwFlags )
+  DWORD dwFlags,
+  BOOL bAnsi )
 {
   lpPlayerData lpPData;
-  ICOM_THIS(IDirectPlay2Impl,iface);
 
-  TRACE("(%p)->(%p,%p,%d,%p,0x%08lx,0x%08lx)\n", This, lpidPlayer, lpPlayerName, hEvent, lpData, dwDataSize, dwFlags );
+  TRACE( "(%p)->(%p,%p,%d,%p,0x%08lx,0x%08lx,%u)\n", 
+         This, lpidPlayer, lpPlayerName, hEvent, lpData, 
+         dwDataSize, dwFlags, bAnsi );
 
   if( dwFlags == 0 ) 
   {
@@ -1144,6 +1198,7 @@
         ( DP_FindPlayer( This, DPID_SERVERPLAYER ) )
       )
     {
+      TRACE( "Denying SERVERPLAYER creation\n" );
       return DPERR_CANTCREATEPLAYER;
     }
 
@@ -1154,8 +1209,8 @@
     *lpidPlayer = DPID_UNKNOWN;
   }
 
-  lpPData = DP_CreatePlayer( iface, lpidPlayer, 
-                             lpPlayerName, hEvent, TRUE /*Ansi*/ );
+  lpPData = DP_CreatePlayer( This, lpidPlayer, 
+                             lpPlayerName, hEvent, bAnsi );
 
   if( lpPData == NULL )
   {
@@ -1174,23 +1229,29 @@
   return DP_OK;
 }
 
+static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
+          ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_CreatePlayer( This, lpidPlayer, lpPlayerName, hEvent, 
+                           lpData, dwDataSize, dwFlags, TRUE );
+}
+
 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
           ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(%p,%p,%d,%p,0x%08lx,0x%08lx): stub\n", This, lpidPlayer, lpPlayerName, hEvent, lpData, dwDataSize, dwFlags );
-  return DP_OK;
+  return DP_IF_CreatePlayer( This, lpidPlayer, lpPlayerName, hEvent, 
+                           lpData, dwDataSize, dwFlags, FALSE );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
-          ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
+static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
+          ( IDirectPlay2Impl* This, DPID idGroup, DPID idPlayer, BOOL bAnsi )
 {
   lpGroupList  lpGList;
   lpPlayerList lpPList;
   
-  ICOM_THIS(IDirectPlay2Impl,iface);
-
-  TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idGroup, idPlayer );
+  TRACE("(%p)->(0x%08lx,0x%08lx,%u)\n", This, idGroup, idPlayer, bAnsi );
 
   /* Find the group */
   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
@@ -1205,7 +1266,7 @@
   }
 
   /* Remove the player shortcut from the group */
-  TAILQ_REMOVE_ENTRY( &lpGList->lpGData->players, players, lpPData->dpid, idPlayer, lpPList );
+  DPQ_REMOVE_ENTRY( lpGList->lpGData->players, players, lpPData->dpid, idPlayer, lpPList );
 
   if( lpPList == NULL )
   {
@@ -1221,17 +1282,24 @@
   return DP_OK;
 }
 
+static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
+          ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_DeletePlayerFromGroup( This, idGroup, idPlayer, TRUE );
+}
+
 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
           ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idPlayer );
-  return DP_OK;
+  return DP_IF_DeletePlayerFromGroup( This, idGroup, idPlayer, FALSE );
 }
 
 typedef struct _DPRGOPContext
 {
   LPDIRECTPLAY3 iface;
+  BOOL          bAnsi;
   DPID          idGroup;
 } DPRGOPContext, *lpDPRGOPContext;
 
@@ -1273,14 +1341,13 @@
   return TRUE; /* Continue enumeration */
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
-          ( LPDIRECTPLAY2A iface, DPID idGroup )
+static HRESULT WINAPI DP_IF_DestroyGroup
+          ( IDirectPlay2Impl* This, DPID idGroup, BOOL bAnsi )
 {
   lpGroupList lpGList;
   DPRGOPContext context;
-  ICOM_THIS(IDirectPlay2Impl,iface);
 
-  FIXME("(%p)->(0x%08lx): semi stub\n", This, idGroup );
+  FIXME("(%p)->(0x%08lx,%u): semi stub\n", This, idGroup, bAnsi );
 
   /* Find the group */
   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
@@ -1291,7 +1358,8 @@
   /* Yes we're performing a dangerous cast, but it will not be used
      unless it's actually a dp3 interface because we will have no
      nested groups to delete and we're performing a check below */
-  context.iface   = (LPDIRECTPLAY3A)iface;
+  context.iface   = (LPDIRECTPLAY3)This;
+  context.bAnsi   = bAnsi;
   context.idGroup = idGroup;
 
   /* We should only concern ourselves with a group having groups if this is
@@ -1299,12 +1367,12 @@
   if( This->dp3 )
   {
     /* Remove all links to groups that this group has since this is dp3 */
-    IDirectPlayX_EnumGroupsInGroup( (LPDIRECTPLAY3A)iface, idGroup, NULL, 
+    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( lpGList->lpGData->parent )
     {
-      IDirectPlayX_DeleteGroupFromGroup( (LPDIRECTPLAY3A)iface, 
+      IDirectPlayX_DeleteGroupFromGroup( (LPDIRECTPLAY3A)This, 
                                          lpGList->lpGData->parent->dpid, 
                                          idGroup ); 
     } 
@@ -1312,7 +1380,7 @@
   }
   
   /* Remove all players that this group has */
-  IDirectPlayX_EnumGroupPlayers( iface, idGroup, NULL, 
+  IDirectPlayX_EnumGroupPlayers( (LPDIRECTPLAY3A)This, idGroup, NULL, 
                                  cbRemoveGroupOrPlayer, (LPVOID)&context, 0 );
 
   /* Now delete this group data and list */
@@ -1323,12 +1391,18 @@
   return DP_OK;
 }
 
+static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
+          ( LPDIRECTPLAY2A iface, DPID idGroup )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_DestroyGroup( This, idGroup, TRUE );
+}
+
 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
           ( LPDIRECTPLAY2 iface, DPID idGroup )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx): stub\n", This, idGroup );
-  return DP_OK;
+  return DP_IF_DestroyGroup( This, idGroup, FALSE );
 }
 
 typedef struct _DPFAGContext
@@ -1337,13 +1411,12 @@
   DPID idPlayer;
 } DPFAGContext, *lpDPFAGContext;
 
-static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
-          ( LPDIRECTPLAY2A iface, DPID idPlayer )
+static HRESULT WINAPI DP_IF_DestroyPlayer
+          ( IDirectPlay2Impl* This, DPID idPlayer, BOOL bAnsi )
 {
   DPFAGContext cbContext;
-  ICOM_THIS(IDirectPlay2Impl,iface);
 
-  FIXME("(%p)->(0x%08lx): semi stub\n", This, idPlayer );
+  FIXME("(%p)->(0x%08lx,%u): semi stub\n", This, idPlayer, bAnsi );
 
   if( DP_FindPlayer( This, idPlayer ) )
   {
@@ -1352,12 +1425,12 @@
 
   /* FIXME: If the player is remote, we must be the host to delete this */
 
-  cbContext.iface = iface;
+  cbContext.iface = (LPDIRECTPLAY2)This;
   cbContext.idPlayer = idPlayer;
 
   /* Find each group and call DeletePlayerFromGroup if the player is a
      member of the group */
-  IDirectPlayX_EnumGroups( iface, NULL, cbDeletePlayerFromAllGroups,
+  IDirectPlayX_EnumGroups( (LPDIRECTPLAY2)This, NULL, cbDeletePlayerFromAllGroups,
                            (LPVOID)&cbContext, DPENUMGROUPS_ALL);
 
   /* Now delete player and player list */
@@ -1396,43 +1469,66 @@
   return TRUE;
 }
 
+static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
+          ( LPDIRECTPLAY2A iface, DPID idPlayer )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_DestroyPlayer( This, idPlayer, TRUE );
+}
 
 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
           ( LPDIRECTPLAY2 iface, DPID idPlayer )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx): stub\n", This, idPlayer );
+  return DP_IF_DestroyPlayer( This, idPlayer, FALSE );
+}
+
+static HRESULT WINAPI DP_IF_EnumGroupPlayers
+          ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
+            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
+{
+  FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): stub\n", 
+          This, idGroup, lpguidInstance, lpEnumPlayersCallback2, 
+          lpContext, dwFlags, bAnsi );
   return DP_OK;
 }
 
 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
-          ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
+          ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
             LPVOID lpContext, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx): stub\n", This, idGroup, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags );
-  return DP_OK;
+  return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
+                               lpEnumPlayersCallback2, lpContext,
+                               dwFlags, TRUE );
 }
 
 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
-          ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
+          ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
             LPVOID lpContext, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx): stub\n", This, idGroup, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags );
-  return DP_OK;
+  return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
+                               lpEnumPlayersCallback2, lpContext,
+                               dwFlags, FALSE );
 }
 
 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
-static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
-          ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI DP_IF_EnumGroups
+          ( IDirectPlay2Impl* This, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
+            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
 {
   lpGroupList lpGList;
-  ICOM_THIS(IDirectPlay2Impl,iface);
 
-  FIXME("(%p)->(%p,%p,%p,0x%08lx): semi stub\n", This, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags );
+  FIXME("(%p)->(%p,%p,%p,0x%08lx,%u): semi stub\n", 
+         This, lpguidInstance, lpEnumPlayersCallback2, 
+         lpContext, dwFlags, bAnsi );
 
-  lpGList = This->dp2->groups.tqh_first; 
+  lpGList = This->dp2->groups.lpQHFirst; 
 
   while( lpGList )
   {
@@ -1451,7 +1547,7 @@
       break; /* User requested break */
     }
 
-    if( ( lpGList = lpGList->groups.tqe_next ) == This->dp2->groups.tqh_first )
+    if( ( lpGList = lpGList->groups.lpQNext ) == This->dp2->groups.lpQHFirst )
     {
       break;
     }
@@ -1460,31 +1556,57 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
-          ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, DWORD dwFlags )
+static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
+          ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
+            LPVOID lpContext, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(%p,%p,%p,0x%08lx): stub\n", This, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags );
+  return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
+                         lpContext, dwFlags, TRUE );
+}
+
+static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
+          ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
+            LPVOID lpContext, DWORD dwFlags )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
+                         lpContext, dwFlags, FALSE );
+}
+
+static HRESULT WINAPI DP_IF_EnumPlayers
+          ( IDirectPlay2Impl* This, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
+            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
+{
+
+  FIXME("(%p)->(%p,%p,%p,0x%08lx,%u): stub\n", 
+          This, lpguidInstance, lpEnumPlayersCallback2, 
+          lpContext, dwFlags, bAnsi );
+
   return DP_OK;
 }
 
 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
-          ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, DWORD dwFlags )
+          ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
+            LPVOID lpContext, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-
-  FIXME("(%p)->(%p,%p,%p,0x%08lx): stub\n", This, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags );
-
-  return DP_OK;
+  return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
+                          lpContext, dwFlags, TRUE );
 }
 
 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
-          ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, DWORD dwFlags )
+          ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance, 
+            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
+            LPVOID lpContext, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(%p,%p,%p,0x%08lx): stub\n", 
-        This, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags );
-  return DP_OK;
+  return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
+                          lpContext, dwFlags, FALSE );
 }
 
 /* This function should call the registered callback function that the user
@@ -1654,14 +1776,14 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
-          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize, DWORD dwFlags )
+static HRESULT WINAPI DP_IF_GetGroupData
+          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, 
+            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
 {
   lpGroupList lpGList;
 
-  ICOM_THIS(IDirectPlay2Impl,iface);
-
-  FIXME("(%p)->(0x%08lx,%p,%p,0x%08lx): dwFlags ignored\n", This, idGroup, lpData, lpdwDataSize, dwFlags );
+  FIXME("(%p)->(0x%08lx,%p,%p,0x%08lx,%u): dwFlags ignored\n", 
+          This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
 
   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
   {
@@ -1682,24 +1804,34 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
-          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize, DWORD dwFlags )
+static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
+          ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData, 
+            LPDWORD lpdwDataSize, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx,%p,%p,0x%08lx): stub\n", This, idGroup, lpData, lpdwDataSize, dwFlags );
-  return DP_OK;
+  return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize, 
+                           dwFlags, TRUE );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
-          ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
+          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, 
+            LPDWORD lpdwDataSize, DWORD dwFlags )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize, 
+                           dwFlags, FALSE );
+}
+
+static HRESULT WINAPI DP_IF_GetGroupName
+          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, 
+            LPDWORD lpdwDataSize, BOOL bAnsi )
 {
   lpGroupList lpGList;
   LPDPNAME    lpName = (LPDPNAME)lpData;
   DWORD       dwRequiredDataSize;
 
-  ICOM_THIS(IDirectPlay2Impl,iface);
-
-  TRACE("(%p)->(0x%08lx,%p,%p)\n", This, idGroup, lpData, lpdwDataSize );
+  FIXME("(%p)->(0x%08lx,%p,%p,%u) ANSI ignored\n", 
+          This, idGroup, lpData, lpdwDataSize, bAnsi );
 
   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
   {
@@ -1752,12 +1884,20 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
-          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
+          ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData, 
+            LPDWORD lpdwDataSize )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idGroup, lpData, lpdwDataSize );
-  return DP_OK;
+  return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
+}
+
+static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
+          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, 
+            LPDWORD lpdwDataSize )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
 }
 
 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
@@ -1808,14 +1948,14 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
-          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize, DWORD dwFlags )
+static HRESULT WINAPI DP_IF_GetPlayerData
+          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, 
+            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
 {
   lpPlayerList lpPList;
 
-  ICOM_THIS(IDirectPlay2Impl,iface);
-
-  FIXME("(%p)->(0x%08lx,%p,%p,0x%08lx): stub\n", This, idPlayer, lpData, lpdwDataSize, dwFlags );
+  FIXME( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u): stub\n", 
+         This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
 
   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
   {
@@ -1836,24 +1976,34 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize, DWORD dwFlags )
+static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
+          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, 
+            LPDWORD lpdwDataSize, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx,%p,%p,0x%08lx): stub\n", This, idPlayer, lpData, lpdwDataSize, dwFlags );
-  return DP_OK;
+  return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize, 
+                            dwFlags, TRUE );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
+          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, 
+            LPDWORD lpdwDataSize, DWORD dwFlags )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize, 
+                            dwFlags, FALSE );
+}
+
+static HRESULT WINAPI DP_IF_GetPlayerName
+          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, 
+            LPDWORD lpdwDataSize, BOOL bAnsi )
 {
   lpPlayerList lpPList;
   LPDPNAME    lpName = (LPDPNAME)lpData;
   DWORD       dwRequiredDataSize;
 
-  ICOM_THIS(IDirectPlay2Impl,iface);
-
-  TRACE("(%p)->(0x%08lx,%p,%p)\n", This, idPlayer, lpData, lpdwDataSize );
+  FIXME( "(%p)->(0x%08lx,%p,%p,%u): ANSI \n", 
+         This, idPlayer, lpData, lpdwDataSize, bAnsi );
 
   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
   {
@@ -1906,12 +2056,20 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
+static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
+          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, 
+            LPDWORD lpdwDataSize )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
-  return DP_OK;
+  return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
+}
+
+static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
+          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, 
+            LPDWORD lpdwDataSize )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
 }
 
 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
@@ -1949,12 +2107,12 @@
 }
 
 
-static HRESULT WINAPI DirectPlay2AImpl_Open
-          ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
+static HRESULT WINAPI DP_SecureOpen
+          ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
+            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
 {
-  ICOM_THIS(IDirectPlay2Impl,iface);
-
-  FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpsd, dwFlags );
+  FIXME( "(%p)->(%p,0x%08lx,%p,%p): semi stub\n", 
+         This, lpsd, dwFlags, lpSecurity, lpCredentials );
 
   if( This->dp2->bConnectionOpen )
   {
@@ -1963,7 +2121,9 @@
   }
 
   /* When we open we need to stop any EnumSession activity */
-  IDirectPlayX_EnumSessions( iface, NULL, 0, NULL, NULL, DPENUMSESSIONS_STOPASYNC ); 
+  /* FIXME: Perhaps some sort of internal interface would be better */
+  IDirectPlayX_EnumSessions( (LPDIRECTPLAY2A)This, NULL, 0, NULL, NULL, 
+                             DPENUMSESSIONS_STOPASYNC ); 
 
   if( dwFlags & DPOPEN_CREATE )
   {
@@ -1984,12 +2144,20 @@
   return DP_OK;
 }
 
+static HRESULT WINAPI DirectPlay2AImpl_Open
+          ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
+  return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL );
+}
+
 static HRESULT WINAPI DirectPlay2WImpl_Open
           ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpsd, dwFlags );
-  return DP_OK;
+  TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
+  return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL );
 }
 
 static HRESULT WINAPI DirectPlay2AImpl_Receive
@@ -2024,13 +2192,14 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
-          ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI DP_IF_SetGroupData
+          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, 
+            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
 {
   lpGroupList lpGList;
-  ICOM_THIS(IDirectPlay2Impl,iface);
 
-  FIXME("(%p)->(0x%08lx,%p,0x%08lx,0x%08lx): dwFlags ignored\n", This, idGroup, lpData, dwDataSize, dwFlags );
+  FIXME( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u): dwFlags ignored\n", 
+         This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
 
   /* Parameter check */
   if( ( lpData == NULL ) &&
@@ -2051,29 +2220,37 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
-          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
-{   
+static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
+          ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData, 
+            DWORD dwDataSize, DWORD dwFlags )
+{  
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx,%p,0x%08lx,0x%08lx): stub\n", This, idGroup, lpData, dwDataSize, dwFlags );
-  return DP_OK;
+  return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
-          ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName, DWORD dwFlags )
+static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
+          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, 
+            DWORD dwDataSize, DWORD dwFlags )
+{   
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
+}
+
+static HRESULT WINAPI DP_IF_SetGroupName
+          ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName, 
+            DWORD dwFlags, BOOL bAnsi )
 {
   lpGroupList lpGList;
 
-  ICOM_THIS(IDirectPlay2Impl,iface);
-
-  TRACE("(%p)->(0x%08lx,%p,0x%08lx)\n", This, idGroup, lpGroupName, dwFlags );
+  TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", This, idGroup, 
+         lpGroupName, dwFlags, bAnsi );
 
   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
   {
     return DPERR_INVALIDGROUP;
   }
 
-  DP_CopyDPNAMEStruct( &lpGList->lpGData->name, lpGroupName, TRUE );
+  DP_CopyDPNAMEStruct( &lpGList->lpGData->name, lpGroupName, bAnsi );
 
   /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
   FIXME( "Message not sent and dwFlags ignored\n" );
@@ -2081,21 +2258,30 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
-          ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName, DWORD dwFlags )
+static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
+          ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName, 
+            DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx,%p,0x%08lx): stub\n", This, idGroup, lpGroupName, dwFlags );
-  return DP_OK;
+  return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
-          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
+          ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName, 
+            DWORD dwFlags )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
+}
+
+static HRESULT WINAPI DP_IF_SetPlayerData
+          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, 
+            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
 {
   lpPlayerList lpPList;
-  ICOM_THIS(IDirectPlay2AImpl,iface);
 
-  TRACE("(%p)->(0x%08lx,%p,0x%08lx,0x%08lx)\n", This, idPlayer, lpData, dwDataSize, dwFlags );
+  TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n", 
+         This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
 
   /* Parameter check */
   if( ( lpData == NULL ) &&
@@ -2121,29 +2307,39 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
+          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, 
+            DWORD dwDataSize, DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx,%p,0x%08lx,0x%08lx): stub\n", This, idPlayer, lpData, dwDataSize, dwFlags );
-  return DP_OK;
+  return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize, 
+                              dwFlags, TRUE );
 }
 
-static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
-          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName, DWORD dwFlags )
+static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
+          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, 
+            DWORD dwDataSize, DWORD dwFlags )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize, 
+                              dwFlags, FALSE );
+}
+
+static HRESULT WINAPI DP_IF_SetPlayerName
+          ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName, 
+            DWORD dwFlags, BOOL bAnsi )
 {
   lpPlayerList lpPList;
 
-  ICOM_THIS(IDirectPlay2AImpl,iface);
-
-  TRACE("(%p)->(0x%08lx,%p,0x%08lx)\n", This, idPlayer, lpPlayerName, dwFlags );
+  TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", 
+         This, idPlayer, lpPlayerName, dwFlags, bAnsi );
 
   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
   {
     return DPERR_INVALIDGROUP;
   }
 
-  DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, TRUE );
+  DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
 
   /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
   FIXME( "Message not sent and dwFlags ignored\n" );
@@ -2151,12 +2347,20 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
-          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName, DWORD dwFlags )
+static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
+          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName, 
+            DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay2Impl,iface);
-  FIXME("(%p)->(0x%08lx,%p,0x%08lx): stub\n", This, idPlayer, lpPlayerName, dwFlags );
-  return DP_OK;
+  return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
+}
+
+static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
+          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName, 
+            DWORD dwFlags )
+{
+  ICOM_THIS(IDirectPlay2Impl,iface);
+  return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
 }
 
 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
@@ -2175,16 +2379,14 @@
   return DP_OK;
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
-          ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
+static HRESULT WINAPI DP_IF_AddGroupToGroup
+          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
 {
   lpGroupList lpGParentList;
   lpGroupList lpGList;
   lpGroupList lpNewGList;
 
-  ICOM_THIS(IDirectPlay3AImpl,iface);
-
-  TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
+  TRACE( "(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
 
   if( ( lpGParentList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
   {
@@ -2208,7 +2410,7 @@
   lpNewGList->lpGData = lpGList->lpGData;
 
   /* Add the player to the list of players for this group */
-  TAILQ_INSERT_TAIL(&lpGList->lpGData->groups,lpNewGList,groups);
+  DPQ_INSERT( lpGList->lpGData->groups, lpNewGList, groups );
 
   /* Send a ADDGROUPTOGROUP message */
   FIXME( "Not sending message\n" );
@@ -2216,24 +2418,32 @@
   return DP_OK;
 }
 
+static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
+          ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
+{
+  ICOM_THIS(IDirectPlay3Impl,iface);
+  return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
+}
+
 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
 {
   ICOM_THIS(IDirectPlay3Impl,iface);
-  FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idParentGroup, idGroup );
-  return DP_OK;
+  return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
-          ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+static HRESULT WINAPI DP_IF_CreateGroupInGroup
+          ( IDirectPlay3Impl* This, DPID idParentGroup, LPDPID lpidGroup, 
+            LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, 
+            DWORD dwFlags )
 {
   lpGroupList lpGParentList;
   lpGroupList lpGList;
   lpGroupData lpGData;
 
-  ICOM_THIS(IDirectPlay3AImpl,iface);
-
-  TRACE("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx)\n", This, idParentGroup, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags );
+  TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx)\n", 
+         This, idParentGroup, lpidGroup, lpGroupName, lpData, 
+         dwDataSize, dwFlags );
 
   /* Verify that the specified parent is valid */
   if( ( lpGParentList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, 
@@ -2265,7 +2475,7 @@
 
   lpGList->lpGData = lpGData; 
 
-  TAILQ_INSERT_TAIL(&lpGParentList->lpGData->groups,lpGList,groups);
+  DPQ_INSERT( lpGParentList->lpGData->groups, lpGList, groups );
  
 
   /* FIXME: Should send DPMSG_CREATEPLAYERORGROUP message to everyone,
@@ -2274,25 +2484,33 @@
   FIXME( "Should broadcast group creation to everything in session\n" );
 
   return DP_OK;
+}
 
-
-  return DP_OK;
+static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
+          ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup, 
+            LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, 
+            DWORD dwFlags )
+{
+  ICOM_THIS(IDirectPlay3Impl,iface);
+  return DP_IF_CreateGroupInGroup( This, idParentGroup, lpidGroup, lpGroupName,
+                                   lpData, dwDataSize, dwFlags );
 }
 
 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
-          ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+          ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup, 
+            LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, 
+            DWORD dwFlags )
 {
   ICOM_THIS(IDirectPlay3Impl,iface);
-  FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx): stub\n", This, idParentGroup, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags );
-  return DP_OK;
+  return DP_IF_CreateGroupInGroup( This, idParentGroup, lpidGroup, lpGroupName,
+                                   lpData, dwDataSize, dwFlags );
 }
 
-static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
-          ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
+static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
+          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
 {
   lpGroupList lpGList;
   lpGroupList lpGParentList;
-  ICOM_THIS(IDirectPlay3AImpl,iface);
 
   TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
 
@@ -2303,7 +2521,7 @@
   } 
 
   /* Remove the group from the parent group queue */
-  TAILQ_REMOVE_ENTRY( &lpGParentList->lpGData->groups, groups, lpGData->dpid, idGroup, lpGList );
+  DPQ_REMOVE_ENTRY( lpGParentList->lpGData->groups, groups, lpGData->dpid, idGroup, lpGList );
 
   if( lpGList == NULL )
   {
@@ -2319,12 +2537,18 @@
   return DP_OK;
 }
 
+static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
+          ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
+{
+  ICOM_THIS(IDirectPlay3Impl,iface);
+  return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
+}
+
 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
 {
   ICOM_THIS(IDirectPlay3Impl,iface);
-  FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idParentGroup, idGroup );
-  return DP_OK;
+  return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
 }
 
 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
@@ -2590,7 +2814,7 @@
     return DPERR_INVALIDGROUP;
   }
 
-  lpGiGList = lpGList->lpGData->groups.tqh_first;
+  lpGiGList = lpGList->lpGData->groups.lpQHFirst;
 
   while( lpGiGList )
   {
@@ -2603,7 +2827,7 @@
        return DP_OK; /* User requested break */
      }
 
-     if( ( lpGiGList = lpGiGList->groups.tqe_next ) == lpGList->lpGData->groups.tqh_first )
+     if( ( lpGiGList = lpGiGList->groups.lpQNext ) == lpGList->lpGData->groups.lpQHFirst )
      {
         return DP_OK; /* End of groups */
      }
@@ -2701,47 +2925,19 @@
 }
 
 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
-          ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags, LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
+          ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags, 
+            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
 {
-  ICOM_THIS(IDirectPlay3Impl,iface);
-
-  FIXME("(%p)->(%p,0x%08lx,%p,%p): stub\n", This, lpsd, dwFlags, lpSecurity, lpCredentials );
-
-  if( This->dp2->bConnectionOpen )
-  {
-    TRACE( ": rejecting already open connection.\n" );
-    return DPERR_ALREADYINITIALIZED;
-  }
-
-  /* When we open we need to stop any EnumSession activity */
-  IDirectPlayX_EnumSessions( iface, NULL, 0, NULL, NULL, DPENUMSESSIONS_STOPASYNC );
-
-  if( dwFlags & DPOPEN_CREATE )
-  {
-    dwFlags &= ~DPOPEN_CREATE;
-
-    /* Rightoo - this computer is the host and the local computer needs to be
-       the name server so that others can join this session */
-    NS_SetLocalComputerAsNameServer( lpsd );
-
-    This->dp2->bHostInterface = TRUE;
-  }
-
-  if( dwFlags )
-  {
-    ERR( ": ignored dwFlags 0x%08lx\n", dwFlags );
-  }
-
-  return DP_OK;
-
+  ICOM_THIS(IDirectPlay2Impl,iface); /* Yes a dp 2 interface */
+  return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials );
 }
 
 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
-          ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags, LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
+          ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags, 
+            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
 {   
-  ICOM_THIS(IDirectPlay3Impl,iface);
-  FIXME("(%p)->(%p,0x%08lx,%p,%p): stub\n", This, lpsd, dwFlags, lpSecurity, lpCredentials );
-  return DP_OK;
+  ICOM_THIS(IDirectPlay2Impl,iface); /* Yes a dp 2 interface */
+  return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials );
 }
 
 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
diff --git a/dlls/dplayx/dplayx_global.c b/dlls/dplayx/dplayx_global.c
index bee0c82..220b263 100644
--- a/dlls/dplayx/dplayx_global.c
+++ b/dlls/dplayx/dplayx_global.c
@@ -14,54 +14,167 @@
 #include "debugtools.h"
 #include "winbase.h"
 #include "winerror.h"
-#include "heap.h"  /* Really shouldn't be using those HEAP_strdupA interfaces should I? */
 
 #include "dplayx_global.h"
+#include "dplayx_messages.h" /* For CreateMessageReceptionThread only */
 
 DEFAULT_DEBUG_CHANNEL(dplay);
 
 /* FIXME: Need to do all that fun other dll referencing type of stuff */
-/* FIXME: Need to allocate a giant static area */
 
 /* Static data for all processes */
-static LPSTR lpszDplayxSemaName = "WINE_DPLAYX_SM";
+static LPCSTR lpszDplayxSemaName = "WINE_DPLAYX_SM";
 static HANDLE hDplayxSema;
 
+static LPCSTR lpszDplayxFileMapping = "WINE_DPLAYX_FM";
+static HANDLE hDplayxSharedMem;
+
+static LPVOID lpSharedStaticData = NULL;
 
 
-#define DPLAYX_AquireSemaphore()  TRACE( "Waiting for DPLAYX sema\n" ); \
-                                  WaitForSingleObject( hDplayxSema, INFINITE ); TRACE( "Through wait\n" )
+#define DPLAYX_AquireSemaphore()  TRACE( "Waiting for DPLAYX semaphore\n" ); \
+                                  WaitForSingleObject( hDplayxSema, INFINITE );\
+                                  TRACE( "Through wait\n" )
+
 #define DPLAYX_ReleaseSemaphore() ReleaseSemaphore( hDplayxSema, 1, NULL ); \
-                                  TRACE( "DPLAYX Sema released\n" ); /* FIXME: Is this correct? */
+                                  TRACE( "DPLAYX Semaphore released\n" ) /* FIXME: Is this correct? */
 
 
 /* HACK for simple global data right now */ 
-enum { numSupportedLobbies = 32, numSupportedSessions = 32 };
-typedef struct tagDirectPlayLobbyData
+#define dwStaticSharedSize (128 * 1024) /* FIXME: Way too much */
+#define dwDynamicSharedSize (128 * 1024) /* FIXME: Enough? */
+#define dwTotalSharedSize  (dwStaticSharedSize + dwDynamicSharedSize)
+
+
+/* FIXME: Is there no easier way? */
+
+/* Pretend the entire dynamic area is carved up into 512 byte blocks.
+ * Each block has 4 bytes which are 0 unless used */
+#define dwBlockSize 512
+#define dwMaxBlock  (dwDynamicSharedSize/dwBlockSize)
+DWORD dwBlockOn  = 0;
+
+typedef struct 
 {
-  /* Just a DPLCONNECTION struct */
-  DWORD           dwConnFlags;
-  DPSESSIONDESC2  sessionDesc;
-  DPNAME          playerName;
-  GUID            guidSP;
-  LPVOID          lpAddress;
-  DWORD           dwAddressSize;
+  DWORD used;
+  DWORD data[dwBlockSize-sizeof(DWORD)];
+} DPLAYX_MEM_SLICE;
+
+DPLAYX_MEM_SLICE* lpMemArea;
+
+void DPLAYX_PrivHeapFree( LPVOID addr );
+void DPLAYX_PrivHeapFree( LPVOID addr )
+{
+  LPVOID lpAddrStart;
+  DWORD dwBlockUsed;
+
+  /* Handle getting passed a NULL */
+  if( addr == NULL )
+  {
+    return;
+  } 
+
+  lpAddrStart = addr - sizeof(DWORD); /* Find block header */
+  dwBlockUsed =  ((BYTE*)lpAddrStart - (BYTE*)lpMemArea)/dwBlockSize;
+  
+  lpMemArea[ dwBlockUsed ].used = 0;
+}
+
+LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size );
+LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size )
+{
+  LPVOID lpvArea = NULL;
+  UINT   uBlockUsed;
+
+  if( size > (dwBlockSize - sizeof(DWORD)) )
+  {
+    FIXME( "Size exceeded. Request of 0x%08lx\n", size );
+    size = dwBlockSize - sizeof(DWORD);
+  } 
+
+  /* Find blank area */
+  uBlockUsed = 0; 
+  while( ( lpMemArea[ uBlockUsed ].used != 0 ) && ( uBlockUsed <= dwMaxBlock ) ) { uBlockUsed++; } 
+
+  if( uBlockUsed <= dwMaxBlock )
+  {
+    /* Set the area used */
+    lpMemArea[ uBlockUsed ].used = 1;
+    lpvArea = &(lpMemArea[ uBlockUsed ].data);
+  }
+  else
+  {
+    ERR( "No free block found\n" );
+    return NULL;
+  }
+  
+  if( flags & HEAP_ZERO_MEMORY )
+  {
+    ZeroMemory( lpvArea, size );
+  }
+
+  return lpvArea;
+}
+
+LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str );
+LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str )
+{
+  LPSTR p = DPLAYX_PrivHeapAlloc( flags, strlen(str) + 1 );
+  if(p) {
+    strcpy( p, str );
+  }
+  return p;
+}
+
+LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str );
+LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str )
+{                   
+  INT len = lstrlenW(str) + 1;
+  LPWSTR p = DPLAYX_PrivHeapAlloc( flags, len * sizeof(WCHAR) );
+  if(p) {
+    lstrcpyW( p, str );
+  }
+  return p;
+}
+
+
+enum { numSupportedLobbies = 32, numSupportedSessions = 32 };
+typedef struct tagDPLAYX_LOBBYDATA
+{
+  /* Points to lpConn + block of contiguous extra memory for dynamic parts
+   * of the struct directly following 
+   */
+  LPDPLCONNECTION lpConn;
 
   /* Information for dplobby interfaces */
   DWORD           dwAppID;
   HANDLE          hReceiveEvent;
   DWORD           dwAppLaunchedFromID;
 
-} DirectPlayLobbyData, *lpDirectPlayLobbyData;
+  /* Should this lobby app send messages to creator at important life
+   * stages
+   */
+  BOOL bInformOnConnect;     /* FIXME: Not used yet */
+  BOOL bInformOnSettingRead;
+  BOOL bInformOnAppDeath;    /* FIXME: Not used yet */
 
-static DirectPlayLobbyData lobbyData[ numSupportedLobbies ];
+  BOOL bWaitForConnectionSettings;
 
-/* Hack for now */
-static DPSESSIONDESC2 sessionData[ numSupportedSessions ];
+} DPLAYX_LOBBYDATA, *LPDPLAYX_LOBBYDATA;
+
+static DPLAYX_LOBBYDATA* lobbyData = NULL;
+/* static DPLAYX_LOBBYDATA lobbyData[ numSupportedLobbies ]; */
+
+static DPSESSIONDESC2* sessionData = NULL; 
+/* static DPSESSIONDESC2* sessionData[ numSupportedSessions ]; */
 
 /* Function prototypes */
-BOOL  DPLAYX_IsAppIdLobbied( DWORD dwAppId, lpDirectPlayLobbyData* dplData );
-void DPLAYX_InitializeLobbyDataEntry( lpDirectPlayLobbyData lpData );
+DWORD DPLAYX_SizeOfLobbyDataA( LPDPLCONNECTION lpDplData );
+DWORD DPLAYX_SizeOfLobbyDataW( LPDPLCONNECTION lpDplData );
+void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src );
+void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src );
+BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppId, LPDPLAYX_LOBBYDATA* dplData );
+void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData );
 BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2  lpSessionDest,
                                    LPCDPSESSIONDESC2 lpSessionSrc );
 
@@ -71,51 +184,153 @@
  * Called to initialize the global data. This will only be used on the 
  * loading of the dll 
  ***************************************************************************/ 
-void DPLAYX_ConstructData(void)
+BOOL DPLAYX_ConstructData(void)
 {
-  UINT i;
+  SECURITY_ATTRIBUTES s_attrib;
+  BOOL                bInitializeSharedMemory = FALSE;
+  LPVOID              lpDesiredMemoryMapStart = (LPVOID)0x50000000;
 
   TRACE( "DPLAYX dll loaded - construct called\n" );
 
-  /* Create a semahopre to block access to DPLAYX global data structs 
-     It starts unblocked, and allows up to 65000 users blocked on it. Seems reasonable
-     for the time being */
-  hDplayxSema = CreateSemaphoreA( NULL, 1, 65000, lpszDplayxSemaName ); 
+  /* Create a semaphore to block access to DPLAYX global data structs */
 
-  if( !hDplayxSema )
+  s_attrib.bInheritHandle       = TRUE;
+  s_attrib.lpSecurityDescriptor = NULL;
+  s_attrib.nLength              = sizeof(s_attrib);
+
+  hDplayxSema = CreateSemaphoreA( &s_attrib, 1, 1, lpszDplayxSemaName ); 
+
+  /* First instance creates the semaphore. Others just use it */
+  if( GetLastError() == ERROR_SUCCESS )
   {
-    /* Really don't have any choice but to continue... */
-    ERR( "Semaphore creation error 0x%08lx\n", GetLastError() );
+    TRACE( "Semaphore %u created\n", hDplayxSema );
+
+    /* The semaphore creator will also build the shared memory */
+    bInitializeSharedMemory = TRUE;
+  }
+  else if ( GetLastError() == ERROR_ALREADY_EXISTS )
+  {
+    TRACE( "Found semaphore handle %u\n", hDplayxSema );
+  }
+  else
+  {
+    ERR( ": semaphore error 0x%08lx\n", GetLastError() );
+    return FALSE;
   }
 
-  /* Set all lobbies to be "empty" */ 
-  for( i=0; i < numSupportedLobbies; i++ )
+  SetLastError( ERROR_SUCCESS );
+
+  DPLAYX_AquireSemaphore();
+ 
+  hDplayxSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE,
+                                         &s_attrib,
+                                         PAGE_READWRITE | SEC_COMMIT,
+                                         0, 
+                                         dwTotalSharedSize,
+                                         lpszDplayxFileMapping ); 
+
+  if( GetLastError() == ERROR_SUCCESS )
   {
-    DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
+    TRACE( "File mapped %u created\n", hDplayxSharedMem );
+  }
+  else if ( GetLastError() == ERROR_ALREADY_EXISTS )
+  {
+    TRACE( "Found FileMapping handle %u\n", hDplayxSharedMem );
+  }
+  else
+  {
+    ERR( ": unable to create shared memory 0x%08lx\n", GetLastError() );
+    return FALSE;
   }
 
-  /* Set all sessions to be "empty" */
-  for( i=0; i < numSupportedSessions; i++ )
+  lpSharedStaticData = MapViewOfFileEx( hDplayxSharedMem, 
+                                        FILE_MAP_WRITE, 
+                                        0, 0, 0, lpDesiredMemoryMapStart );
+
+  if( lpSharedStaticData == NULL )
   {
-    sessionData[i].dwSize = 0;
+    ERR( ": unable to map static data into process memory space: 0x%08lx\n", 
+         GetLastError() );
+    return FALSE;
+  }
+  else
+  {
+    if( lpDesiredMemoryMapStart == lpSharedStaticData )
+    {
+      TRACE( "File mapped to %p\n", lpSharedStaticData );
+    }
+    else
+    {
+      /* Presently the shared data structures use pointers. If the
+       * files are no mapped into the same area, the pointers will no
+       * longer make any sense :(
+       * FIXME: In the future make the shared data structures have some
+       *        sort of fixup to make them independent between data spaces.
+       *        This will also require a rework of the session data stuff.
+       */
+      ERR( "File mapped to %p (not %p). Expect failure\n",
+            lpSharedStaticData, lpDesiredMemoryMapStart );
+    }
   }
 
+  /* Dynamic area starts just after the static area */
+  lpMemArea = (LPVOID)((BYTE*)lpSharedStaticData + dwStaticSharedSize);
+
+  /* FIXME: Crude hack */
+  lobbyData   = (DPLAYX_LOBBYDATA*)lpSharedStaticData;
+  sessionData = (DPSESSIONDESC2*)((BYTE*)lpSharedStaticData + (dwStaticSharedSize/2));
+
+  /* Initialize shared data segments. */
+  if( bInitializeSharedMemory )
+  {
+    UINT i;
+
+    TRACE( "Initializing shared memory\n" );
+
+    /* Set all lobbies to be "empty" */ 
+    for( i=0; i < numSupportedLobbies; i++ )
+    {
+      DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
+    }
+
+    /* Set all sessions to be "empty" */
+    for( i=0; i < numSupportedSessions; i++ )
+    {
+      sessionData[i].dwSize = 0;
+    }
+
+    /* Zero out the dynmaic area */
+    ZeroMemory( lpMemArea, dwDynamicSharedSize );
+
+    /* Just for fun sync the whole data area */
+    FlushViewOfFile( lpSharedStaticData, dwTotalSharedSize );
+  }
+  
+  DPLAYX_ReleaseSemaphore();
+
+  return TRUE;
 }
 
 /*************************************************************************** 
  * Called to destroy all global data. This will only be used on the 
  * unloading of the dll 
  ***************************************************************************/ 
-void DPLAYX_DestructData(void)
+BOOL DPLAYX_DestructData(void)
 {
   TRACE( "DPLAYX dll unloaded - destruct called\n" );
 
-  /* delete the semaphore */
+  /* Delete the semaphore */
   CloseHandle( hDplayxSema );
+ 
+  /* Delete shared memory file mapping */
+  UnmapViewOfFile( lpSharedStaticData );
+  CloseHandle( hDplayxSharedMem );
+
+  return FALSE;
 }
 
 
-void DPLAYX_InitializeLobbyDataEntry( lpDirectPlayLobbyData lpData )
+void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData )
 {
   ZeroMemory( lpData, sizeof( *lpData ) );
 
@@ -127,9 +342,9 @@
  * TRUE/FALSE with a pointer to it's data returned. Pointer data is
  * is only valid if TRUE is returned.
  */
-BOOL  DPLAYX_IsAppIdLobbied( DWORD dwAppID, lpDirectPlayLobbyData* lplpDplData )
+BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppID, LPDPLAYX_LOBBYDATA* lplpDplData )
 {
-  INT i;
+  UINT i;
 
   *lplpDplData = NULL;
 
@@ -144,6 +359,7 @@
     if( lobbyData[ i ].dwAppID == dwAppID )
     {
       /* This process is lobbied */ 
+      TRACE( "Found 0x%08lx @ %u\n", dwAppID, i );
       *lplpDplData = &lobbyData[ i ];
       return TRUE;
     }
@@ -171,15 +387,24 @@
     if( lobbyData[ i ].dwAppID == 0 )
     {
       /* This process is now lobbied */
-      lobbyData[ i ].dwAppID             = dwAppID;
-      lobbyData[ i ].hReceiveEvent       = hReceiveEvent;
-      lobbyData[ i ].dwAppLaunchedFromID = GetCurrentProcessId();
+      TRACE( "Setting lobbyData[%u] for (0x%08lx,%u,0x%08lx)\n",
+              i, dwAppID, hReceiveEvent, GetCurrentProcessId() );
+
+      lobbyData[ i ].dwAppID              = dwAppID;
+      lobbyData[ i ].hReceiveEvent        = hReceiveEvent;
+      lobbyData[ i ].dwAppLaunchedFromID  = GetCurrentProcessId();
+
+      lobbyData[ i ].bInformOnConnect     = TRUE;
+      lobbyData[ i ].bInformOnSettingRead = TRUE;
+      lobbyData[ i ].bInformOnAppDeath    = TRUE;
 
       DPLAYX_ReleaseSemaphore();
       return TRUE;
     }
   }
 
+  ERR( "No empty lobbies\n" );
+
   DPLAYX_ReleaseSemaphore();
   return FALSE;
 }
@@ -196,7 +421,9 @@
   {
     if( lobbyData[ i ].dwAppID == dwAppID )
     {
+      /* FIXME: Should free up anything unused. Tisk tisk :0 */
       /* Mark this entry unused */
+      TRACE( "Marking lobbyData[%u] unused\n", i );
       DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
 
       DPLAYX_ReleaseSemaphore();
@@ -212,20 +439,11 @@
 HRESULT DPLAYX_GetConnectionSettingsA
 ( DWORD dwAppID,
   LPVOID lpData,
-  LPDWORD lpdwDataSize )
+  LPDWORD lpdwDataSize,
+  LPBOOL  lpbSendHaveReadMessage )
 {
-  lpDirectPlayLobbyData lpDplData;
-  LPDPLCONNECTION lpDplConnection;
-
-  /* Verify buffer size */
-  if ( ( lpData == NULL ) ||
-       ( *lpdwDataSize < sizeof( DPLCONNECTION ) )
-     )
-  {
-    *lpdwDataSize = sizeof( DPLCONNECTION );
-
-    return DPERR_BUFFERTOOSMALL;
-  }
+  LPDPLAYX_LOBBYDATA lpDplData;
+  DWORD              dwRequiredDataSize = 0;
 
   DPLAYX_AquireSemaphore();
 
@@ -237,80 +455,109 @@
     return DPERR_NOTLOBBIED;
   }
 
-  /* Copy the information */
-  lpDplConnection = (LPDPLCONNECTION)lpData;
+  dwRequiredDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn );
 
-  /* Copy everything we've got into here */
-  /* Need to actually store the stuff here. Check if we've already allocated each field first. */
-  lpDplConnection->dwSize = sizeof( DPLCONNECTION );
-  lpDplConnection->dwFlags = lpDplData->dwConnFlags;
-
-  /* Copy LPDPSESSIONDESC2 struct */
-  lpDplConnection->lpSessionDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->sessionDesc ) );
-  memcpy( lpDplConnection->lpSessionDesc, &lpDplData->sessionDesc, sizeof( lpDplData->sessionDesc ) );
-
-  if( lpDplData->sessionDesc.sess.lpszSessionNameA )
+  /* Do they want to know the required buffer size or is the provided buffer
+   * big enough? 
+   */
+  if ( ( lpData == NULL ) ||
+       ( *lpdwDataSize < dwRequiredDataSize )
+     )
   {
-    lpDplConnection->lpSessionDesc->sess.lpszSessionNameA =
-      HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.sess.lpszSessionNameA );
+    DPLAYX_ReleaseSemaphore();
+
+    *lpdwDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn );
+
+    return DPERR_BUFFERTOOSMALL;
   }
 
-  if( lpDplData->sessionDesc.pass.lpszPasswordA )
-  {
-    lpDplConnection->lpSessionDesc->pass.lpszPasswordA =
-      HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.pass.lpszPasswordA );
-  }
+  /* They have gotten the information */
+  *lpbSendHaveReadMessage = lpDplData->bInformOnSettingRead;
+  lpDplData->bInformOnSettingRead = FALSE;
 
-  lpDplConnection->lpSessionDesc->dwReserved1 = lpDplData->sessionDesc.dwReserved1;
-  lpDplConnection->lpSessionDesc->dwReserved2 = lpDplData->sessionDesc.dwReserved2;
-
-  /* Copy DPNAME struct - seems to be optional - check for existance first */
-  lpDplConnection->lpPlayerName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->playerName ) );
-  memcpy( lpDplConnection->lpPlayerName, &(lpDplData->playerName), sizeof( lpDplData->playerName ) );
-
-  if( lpDplData->playerName.psn.lpszShortNameA )
-  {
-    lpDplConnection->lpPlayerName->psn.lpszShortNameA =
-      HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.psn.lpszShortNameA );
-  }
-
-  if( lpDplData->playerName.pln.lpszLongNameA )
-  {
-    lpDplConnection->lpPlayerName->pln.lpszLongNameA =
-      HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.pln.lpszLongNameA );
-  }
-
-  memcpy( &lpDplConnection->guidSP, &lpDplData->guidSP, sizeof( lpDplData->guidSP ) );
-
-  lpDplConnection->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->dwAddressSize );
-  memcpy( lpDplConnection->lpAddress, lpDplData->lpAddress, lpDplData->dwAddressSize );
-
-  lpDplConnection->dwAddressSize = lpDplData->dwAddressSize;
-
-  /* FIXME: Send a message - or only the first time? */
+  DPLAYX_CopyConnStructA( (LPDPLCONNECTION)lpData, lpDplData->lpConn );
 
   DPLAYX_ReleaseSemaphore();
 
   return DP_OK;
 }
 
+/* Assumption: Enough contiguous space was allocated at dest */
+void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src )
+{
+  BYTE*              lpStartOfFreeSpace;
+
+  memcpy( dest, src, sizeof( DPLCONNECTION ) );
+
+  lpStartOfFreeSpace = ((BYTE*)dest) + sizeof( DPLCONNECTION );
+
+  /* Copy the LPDPSESSIONDESC2 structure if it exists */
+  if( src->lpSessionDesc )
+  {
+    dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
+    lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
+    memcpy( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) );
+
+    /* Session names may or may not exist */
+    if( src->lpSessionDesc->sess.lpszSessionNameA )
+    {
+      lstrcpyA( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->sess.lpszSessionNameA );
+      dest->lpSessionDesc->sess.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
+      lpStartOfFreeSpace +=  
+        lstrlenA( (LPSTR)dest->lpSessionDesc->sess.lpszSessionName ) + 1;
+    }
+
+    if( src->lpSessionDesc->pass.lpszPasswordA )
+    {
+      lstrcpyA( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->pass.lpszPasswordA );
+      dest->lpSessionDesc->pass.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
+      lpStartOfFreeSpace += 
+        lstrlenA( (LPSTR)dest->lpSessionDesc->pass.lpszPasswordA ) + 1;
+    }
+  }
+
+  /* DPNAME structure is optional */
+  if( src->lpPlayerName )
+  {
+    dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
+    lpStartOfFreeSpace += sizeof( DPNAME );
+    memcpy( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) );
+
+    if( src->lpPlayerName->psn.lpszShortNameA )
+    {
+      lstrcpyA( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->psn.lpszShortNameA );
+      dest->lpPlayerName->psn.lpszShortNameA = (LPSTR)lpStartOfFreeSpace;
+      lpStartOfFreeSpace +=  
+        lstrlenA( (LPSTR)dest->lpPlayerName->psn.lpszShortNameA ) + 1;
+    }
+
+    if( src->lpPlayerName->pln.lpszLongNameA )
+    {
+      lstrcpyA( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->pln.lpszLongNameA );
+      dest->lpPlayerName->pln.lpszLongNameA = (LPSTR)lpStartOfFreeSpace;
+      lpStartOfFreeSpace +=  
+        lstrlenA( (LPSTR)dest->lpPlayerName->pln.lpszLongName ) + 1 ;
+    }
+
+  }
+
+  /* Copy address if it exists */
+  if( src->lpAddress )
+  {
+    dest->lpAddress = (LPVOID)lpStartOfFreeSpace;
+    memcpy( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );
+    /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */
+  }
+}
+
 HRESULT DPLAYX_GetConnectionSettingsW
 ( DWORD dwAppID,
   LPVOID lpData,
-  LPDWORD lpdwDataSize )
+  LPDWORD lpdwDataSize,
+  LPBOOL  lpbSendHaveReadMessage )
 {
-  lpDirectPlayLobbyData lpDplData;
-  LPDPLCONNECTION lpDplConnection;
-
-  /* Verify buffer size */
-  if ( ( lpData == NULL ) ||
-       ( *lpdwDataSize < sizeof( DPLCONNECTION ) )
-     )
-  {
-    *lpdwDataSize = sizeof( DPLCONNECTION );
-
-    return DPERR_BUFFERTOOSMALL;
-  }
+  LPDPLAYX_LOBBYDATA lpDplData;
+  DWORD              dwRequiredDataSize = 0;
 
   DPLAYX_AquireSemaphore();
 
@@ -320,70 +567,112 @@
     return DPERR_NOTLOBBIED;
   }
 
-  /* Copy the information */
-  lpDplConnection = (LPDPLCONNECTION)lpData;
+  dwRequiredDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn );
 
-  /* Copy everything we've got into here */
-  /* Need to actually store the stuff here. Check if we've already allocated each field first. */
-  lpDplConnection->dwSize = sizeof( DPLCONNECTION );
-  lpDplConnection->dwFlags = lpDplData->dwConnFlags;
-
-  /* Copy LPDPSESSIONDESC2 struct */
-  lpDplConnection->lpSessionDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->sessionDesc ) );
-  memcpy( lpDplConnection->lpSessionDesc, &lpDplData->sessionDesc, sizeof( lpDplData->sessionDesc ) );
-
-  if( lpDplData->sessionDesc.sess.lpszSessionName )
+  /* Do they want to know the required buffer size or is the provided buffer
+   * big enough? 
+   */
+  if ( ( lpData == NULL ) ||
+       ( *lpdwDataSize < dwRequiredDataSize )
+     )
   {
-    lpDplConnection->lpSessionDesc->sess.lpszSessionName =
-      HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.sess.lpszSessionName );
+    DPLAYX_ReleaseSemaphore();
+
+    *lpdwDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn );
+
+    return DPERR_BUFFERTOOSMALL;
   }
 
-  if( lpDplData->sessionDesc.pass.lpszPassword )
-  {
-    lpDplConnection->lpSessionDesc->pass.lpszPassword =
-      HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.pass.lpszPassword );
-  }
+  /* They have gotten the information */
+  *lpbSendHaveReadMessage = lpDplData->bInformOnSettingRead;
+  lpDplData->bInformOnSettingRead = FALSE;
 
-  lpDplConnection->lpSessionDesc->dwReserved1 = lpDplData->sessionDesc.dwReserved1;
-  lpDplConnection->lpSessionDesc->dwReserved2 = lpDplData->sessionDesc.dwReserved2;
-
-  /* Copy DPNAME struct - seems to be optional - check for existance first */
-  lpDplConnection->lpPlayerName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->playerName ) );
-  memcpy( lpDplConnection->lpPlayerName, &(lpDplData->playerName), sizeof( lpDplData->playerName ) );
-
-  if( lpDplData->playerName.psn.lpszShortName )
-  {
-    lpDplConnection->lpPlayerName->psn.lpszShortName =
-      HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.psn.lpszShortName );
-  }
-
-  if( lpDplData->playerName.pln.lpszLongName )
-  {
-    lpDplConnection->lpPlayerName->pln.lpszLongName =
-      HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.pln.lpszLongName );
-  }
-
-  memcpy( &lpDplConnection->guidSP, &lpDplData->guidSP, sizeof( lpDplData->guidSP ) );
-
-  lpDplConnection->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->dwAddressSize );
-  memcpy( lpDplConnection->lpAddress, lpDplData->lpAddress, lpDplData->dwAddressSize );
-
-  lpDplConnection->dwAddressSize = lpDplData->dwAddressSize;
-
-  /* FIXME: Send a message - or only the first time? */
+  DPLAYX_CopyConnStructW( (LPDPLCONNECTION)lpData, lpDplData->lpConn );
 
   DPLAYX_ReleaseSemaphore();
 
   return DP_OK;
 }
 
+/* Assumption: Enough contiguous space was allocated at dest */
+void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src )
+{
+  BYTE*              lpStartOfFreeSpace;
 
+  memcpy( dest, src, sizeof( DPLCONNECTION ) );
+
+  lpStartOfFreeSpace = ( (BYTE*)dest) + sizeof( DPLCONNECTION );
+
+  /* Copy the LPDPSESSIONDESC2 structure if it exists */
+  if( src->lpSessionDesc )
+  {
+    dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
+    lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
+    memcpy( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) ); 
+
+    /* Session names may or may not exist */
+    if( src->lpSessionDesc->sess.lpszSessionName )
+    {
+      lstrcpyW( (LPWSTR)lpStartOfFreeSpace, dest->lpSessionDesc->sess.lpszSessionName );
+      src->lpSessionDesc->sess.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
+      lpStartOfFreeSpace +=  sizeof(WCHAR) *
+        ( lstrlenW( (LPWSTR)dest->lpSessionDesc->sess.lpszSessionName ) + 1 );
+    }
+
+    if( src->lpSessionDesc->pass.lpszPassword )
+    {
+      lstrcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpSessionDesc->pass.lpszPassword );
+      dest->lpSessionDesc->pass.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
+      lpStartOfFreeSpace +=  sizeof(WCHAR) *
+        ( lstrlenW( (LPWSTR)dest->lpSessionDesc->pass.lpszPassword ) + 1 );
+    }
+  }
+
+  /* DPNAME structure is optional */
+  if( src->lpPlayerName )
+  {
+    dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
+    lpStartOfFreeSpace += sizeof( DPNAME );
+    memcpy( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) );
+   
+    if( src->lpPlayerName->psn.lpszShortName )
+    {
+      lstrcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->psn.lpszShortName );
+      dest->lpPlayerName->psn.lpszShortName = (LPWSTR)lpStartOfFreeSpace;
+      lpStartOfFreeSpace +=  sizeof(WCHAR) *
+        ( lstrlenW( (LPWSTR)dest->lpPlayerName->psn.lpszShortName ) + 1 );
+    }
+
+    if( src->lpPlayerName->pln.lpszLongName )
+    {
+      lstrcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->pln.lpszLongName );
+      dest->lpPlayerName->pln.lpszLongName = (LPWSTR)lpStartOfFreeSpace;
+      lpStartOfFreeSpace +=  sizeof(WCHAR) *
+        ( lstrlenW( (LPWSTR)dest->lpPlayerName->pln.lpszLongName ) + 1 );
+    }
+
+  }
+
+  /* Copy address if it exists */
+  if( src->lpAddress )
+  {
+    dest->lpAddress = (LPVOID)lpStartOfFreeSpace;
+    memcpy( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );  
+    /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */
+  }
+
+}
+
+/* Store the structure into the shared data structre. Ensure that allocs for
+ * variable length strings come from the shared data structure.
+ * FIXME: We need to free information as well 
+ */
 HRESULT DPLAYX_SetConnectionSettingsA
 ( DWORD dwFlags,
   DWORD dwAppID,
   LPDPLCONNECTION lpConn )
 {
-  lpDirectPlayLobbyData lpDplData;
+  LPDPLAYX_LOBBYDATA lpDplData;
 
   /* Paramater check */
   if( dwFlags || !lpConn )
@@ -401,35 +690,15 @@
     return DPERR_INVALIDPARAMS;
   }
 
-  if( dwAppID == 0 )
-  {
-    dwAppID = GetCurrentProcessId();
-  }
-
   DPLAYX_AquireSemaphore();
 
   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
   {
-    /* FIXME: Create a new entry for this dwAppID? */
     DPLAYX_ReleaseSemaphore();
 
-    return DPERR_GENERIC;
+    return DPERR_NOTLOBBIED;
   }
 
-  /* Store information */
-  if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
-  {
-    DPLAYX_ReleaseSemaphore();
-
-    ERR(": old/new DPLCONNECTION type? Size=%lu vs. expected=%u bytes\n",
-         lpConn->dwSize, sizeof( DPLCONNECTION ) );
-
-    return DPERR_INVALIDPARAMS;
-  }
-
-  /* Need to investigate the lpConn->lpSessionDesc to figure out
-   * what type of session we need to join/create.
-   */
   if(  (!lpConn->lpSessionDesc ) ||
        ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
     )
@@ -442,61 +711,32 @@
     return DPERR_INVALIDPARAMS;
   }
 
-  /* FIXME: How do I store this stuff so that it can be read by all processes? Static area? What about strings? Ewww...large global shared */ 
+  /* Free the existing memory */
+  DPLAYX_PrivHeapFree( lpDplData->lpConn );
 
-  /* Need to actually store the stuff here. Check if we've already allocated each field first. */
-  lpDplData->dwConnFlags = lpConn->dwFlags;
+  lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, 
+                                            DPLAYX_SizeOfLobbyDataA( lpConn ) );
 
-  /* Copy LPDPSESSIONDESC2 struct - this is required */
-  memcpy( &lpDplData->sessionDesc, lpConn->lpSessionDesc, sizeof( *(lpConn->lpSessionDesc) ) );
+  DPLAYX_CopyConnStructA( lpDplData->lpConn, lpConn );
 
-  /* FIXME: Can this just be shorted? Does it handle the NULL case correctly? */
-  if( lpConn->lpSessionDesc->sess.lpszSessionNameA )
-    lpDplData->sessionDesc.sess.lpszSessionNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->sess.lpszSessionNameA );
-  else
-    lpDplData->sessionDesc.sess.lpszSessionNameA = NULL;
-
-  if( lpConn->lpSessionDesc->pass.lpszPasswordA )
-    lpDplData->sessionDesc.pass.lpszPasswordA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->pass.lpszPasswordA );
-  else
-    lpDplData->sessionDesc.pass.lpszPasswordA = NULL;
-
-  lpDplData->sessionDesc.dwReserved1 = lpConn->lpSessionDesc->dwReserved1;
-  lpDplData->sessionDesc.dwReserved2 = lpConn->lpSessionDesc->dwReserved2;
-
-  /* Copy DPNAME struct - seems to be optional - check for existance first */
-  if( lpConn->lpPlayerName )
-  {
-     memcpy( &lpDplData->playerName, lpConn->lpPlayerName, sizeof( *lpConn->lpPlayerName ) );
-
-     if( lpConn->lpPlayerName->psn.lpszShortNameA )
-       lpDplData->playerName.psn.lpszShortNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->psn.lpszShortNameA );
-
-     if( lpConn->lpPlayerName->pln.lpszLongNameA )
-       lpDplData->playerName.pln.lpszLongNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->pln.lpszLongNameA );
-
-  }
-
-  memcpy( &lpDplData->guidSP, &lpConn->guidSP, sizeof( lpConn->guidSP ) );
-
-  lpDplData->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->dwAddressSize );
-  memcpy( lpDplData->lpAddress, lpConn->lpAddress, lpConn->dwAddressSize );
-
-  lpDplData->dwAddressSize = lpConn->dwAddressSize;
-
-  /* FIXME: Send a message - I think */
 
   DPLAYX_ReleaseSemaphore();
 
+  /* FIXME: Send a message - I think */
+
   return DP_OK;
 }
 
+/* Store the structure into the shared data structre. Ensure that allocs for
+ * variable length strings come from the shared data structure.
+ * FIXME: We need to free information as well 
+ */
 HRESULT DPLAYX_SetConnectionSettingsW
 ( DWORD dwFlags,
   DWORD dwAppID,
   LPDPLCONNECTION lpConn )
 {
-  lpDirectPlayLobbyData lpDplData;
+  LPDPLAYX_LOBBYDATA lpDplData;
 
   /* Paramater check */
   if( dwFlags || !lpConn )
@@ -514,88 +754,135 @@
     return DPERR_INVALIDPARAMS;
   }
 
-  if( dwAppID == 0 )
-  {
-    dwAppID = GetCurrentProcessId();
-  }
-
   DPLAYX_AquireSemaphore();
 
   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
   {
     DPLAYX_ReleaseSemaphore();
+
     return DPERR_NOTLOBBIED;
   }
 
-  /* Need to investigate the lpConn->lpSessionDesc to figure out
-   * what type of session we need to join/create.
-   */
-  if(  (!lpConn->lpSessionDesc ) ||
-       ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
-    )
-  {
-    DPLAYX_ReleaseSemaphore();
+  /* Free the existing memory */
+  DPLAYX_PrivHeapFree( lpDplData->lpConn );
 
-    ERR("DPSESSIONDESC passed in? Size=%lu vs. expected=%u bytes\n",
-         lpConn->lpSessionDesc->dwSize, sizeof( DPSESSIONDESC2 ) );
+  lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
+                                            DPLAYX_SizeOfLobbyDataW( lpConn ) );
 
-    return DPERR_INVALIDPARAMS;
-  }
+  DPLAYX_CopyConnStructW( lpDplData->lpConn, lpConn );
 
-  /* FIXME: How do I store this stuff so that it can be read by all processes? Static area? What about strings? Ewww...large global shared */ 
-
-  /* Need to actually store the stuff here. Check if we've already allocated each field first. */
-  lpDplData->dwConnFlags = lpConn->dwFlags;
-
-  /* Copy LPDPSESSIONDESC2 struct - this is required */
-  memcpy( &lpDplData->sessionDesc, lpConn->lpSessionDesc, sizeof( *(lpConn->lpSessionDesc) ) );
-
-  /* FIXME: Can this just be shorted? Does it handle the NULL case correctly? */
-  if( lpConn->lpSessionDesc->sess.lpszSessionName )
-    lpDplData->sessionDesc.sess.lpszSessionName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->sess.lpszSessionName );
-  else
-    lpDplData->sessionDesc.sess.lpszSessionName = NULL;
-
-  if( lpConn->lpSessionDesc->pass.lpszPassword )
-    lpDplData->sessionDesc.pass.lpszPassword = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->pass.lpszPassword );
-  else
-    lpDplData->sessionDesc.pass.lpszPassword = NULL;
-
-  lpDplData->sessionDesc.dwReserved1 = lpConn->lpSessionDesc->dwReserved1;
-  lpDplData->sessionDesc.dwReserved2 = lpConn->lpSessionDesc->dwReserved2;
-
-  /* Copy DPNAME struct - seems to be optional - check for existance first */
-  if( lpConn->lpPlayerName )
-  {
-     memcpy( &lpDplData->playerName, lpConn->lpPlayerName, sizeof( *lpConn->lpPlayerName ) );
-
-     if( lpConn->lpPlayerName->psn.lpszShortName )
-       lpDplData->playerName.psn.lpszShortName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->psn.lpszShortName );
-
-     if( lpConn->lpPlayerName->pln.lpszLongName )
-       lpDplData->playerName.pln.lpszLongName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->pln.lpszLongName );
-
-  }
-
-  memcpy( &lpDplData->guidSP, &lpConn->guidSP, sizeof( lpConn->guidSP ) );
-
-  lpDplData->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->dwAddressSize );
-  memcpy( lpDplData->lpAddress, lpConn->lpAddress, lpConn->dwAddressSize );
-
-  lpDplData->dwAddressSize = lpConn->dwAddressSize;
-
-  /* FIXME: Send a message - I think */
 
   DPLAYX_ReleaseSemaphore();
 
+  /* FIXME: Send a message - I think */
+
   return DP_OK;
 }
 
+DWORD DPLAYX_SizeOfLobbyDataA( LPDPLCONNECTION lpConn )
+{
+  DWORD dwTotalSize = sizeof( DPLCONNECTION );
+
+  /* Just a safety check */
+  if( lpConn == NULL )
+  {
+    ERR( "lpConn is NULL\n" );
+    return 0;
+  }
+
+  if( lpConn->lpSessionDesc != NULL )
+  {
+    dwTotalSize += sizeof( DPSESSIONDESC2 );
+
+    if( lpConn->lpSessionDesc->sess.lpszSessionNameA )
+    {
+      dwTotalSize += lstrlenA( lpConn->lpSessionDesc->sess.lpszSessionNameA ) + 1;
+    }
+ 
+    if( lpConn->lpSessionDesc->pass.lpszPasswordA )
+    {
+      dwTotalSize += lstrlenA( lpConn->lpSessionDesc->pass.lpszPasswordA ) + 1;
+    }
+  }
+
+  if( lpConn->lpPlayerName != NULL )
+  {
+    dwTotalSize += sizeof( DPNAME );
+
+    if( lpConn->lpPlayerName->psn.lpszShortNameA )
+    {
+      dwTotalSize += lstrlenA( lpConn->lpPlayerName->psn.lpszShortNameA ) + 1;
+    }
+
+    if( lpConn->lpPlayerName->pln.lpszLongNameA )
+    {
+      dwTotalSize += lstrlenA( lpConn->lpPlayerName->pln.lpszLongNameA ) + 1;
+    }
+
+  }
+
+  dwTotalSize += lpConn->dwAddressSize;
+
+  return dwTotalSize;
+}
+
+DWORD DPLAYX_SizeOfLobbyDataW( LPDPLCONNECTION lpConn )
+{
+  DWORD dwTotalSize = sizeof( DPLCONNECTION );
+
+  /* Just a safety check */
+  if( lpConn == NULL )
+  {
+    ERR( "lpConn is NULL\n" );
+    return 0;
+  }
+
+  if( lpConn->lpSessionDesc != NULL )
+  {
+    dwTotalSize += sizeof( DPSESSIONDESC2 );
+
+    if( lpConn->lpSessionDesc->sess.lpszSessionName )
+    {
+      dwTotalSize += sizeof( WCHAR ) *
+        ( lstrlenW( lpConn->lpSessionDesc->sess.lpszSessionName ) + 1 );
+    }
+
+    if( lpConn->lpSessionDesc->pass.lpszPassword )
+    {
+      dwTotalSize += sizeof( WCHAR ) *
+        ( lstrlenW( lpConn->lpSessionDesc->pass.lpszPassword ) + 1 );
+    }
+  }
+
+  if( lpConn->lpPlayerName != NULL )
+  {
+    dwTotalSize += sizeof( DPNAME );
+
+    if( lpConn->lpPlayerName->psn.lpszShortName )
+    {
+      dwTotalSize += sizeof( WCHAR ) *
+        ( lstrlenW( lpConn->lpPlayerName->psn.lpszShortName ) + 1 );
+    }
+
+    if( lpConn->lpPlayerName->pln.lpszLongName )
+    {
+      dwTotalSize += sizeof( WCHAR ) *
+        ( lstrlenW( lpConn->lpPlayerName->pln.lpszLongName ) + 1 );
+    }
+
+  }
+
+  dwTotalSize += lpConn->dwAddressSize;
+
+  return dwTotalSize;
+}
+
+
+
 LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateSessionDesc2A( LPCDPSESSIONDESC2 lpSessionSrc )
 {
-   LPDPSESSIONDESC2 lpSessionDest = (LPDPSESSIONDESC2) HeapAlloc( GetProcessHeap(),
-                                                    HEAP_ZERO_MEMORY, 
-                                                    sizeof( *lpSessionSrc ) );
+   LPDPSESSIONDESC2 lpSessionDest = 
+     (LPDPSESSIONDESC2)DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, sizeof( *lpSessionSrc ) );
    DPLAYX_CopyIntoSessionDesc2A( lpSessionDest, lpSessionSrc );
 
    return lpSessionDest;
@@ -610,12 +897,12 @@
   if( lpSessionSrc->sess.lpszSessionNameA )
   {
     lpSessionDest->sess.lpszSessionNameA =
-      HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpSessionSrc->sess.lpszSessionNameA );
+      DPLAYX_strdupA( HEAP_ZERO_MEMORY, lpSessionSrc->sess.lpszSessionNameA );
   }
   if( lpSessionSrc->pass.lpszPasswordA )
   {
     lpSessionDest->pass.lpszPasswordA =
-      HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpSessionSrc->pass.lpszPasswordA );
+      DPLAYX_strdupA( HEAP_ZERO_MEMORY, lpSessionSrc->pass.lpszPasswordA );
   }
 
   return TRUE;
@@ -657,8 +944,6 @@
 {
   UINT i;
 
-  FIXME( ": stub\n" );
-
   /* FIXME: Is this an error if it exists already? */
  
   /* Crude/wrong implementation for now. Just always add to first empty spot */
@@ -674,6 +959,49 @@
 
 }
 
+BOOL DPLAYX_WaitForConnectionSettings( BOOL bWait )
+{
+  LPDPLAYX_LOBBYDATA lpLobbyData;
+
+  DPLAYX_AquireSemaphore();
+  
+  if( !DPLAYX_IsAppIdLobbied( 0, &lpLobbyData ) )
+  {
+    DPLAYX_ReleaseSemaphore();
+    return FALSE;
+  }
+
+  lpLobbyData->bWaitForConnectionSettings = bWait;
+
+  DPLAYX_ReleaseSemaphore();
+
+  return TRUE;
+}
+
+BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void)
+{
+  UINT i;
+  BOOL bFound = FALSE;
+
+  DPLAYX_AquireSemaphore();
+
+  for( i=0; i < numSupportedLobbies; i++ )
+  {
+    if( ( lobbyData[ i ].dwAppID != 0 ) &&            /* lobby initialized */
+        ( lobbyData[ i ].bWaitForConnectionSettings ) /* Waiting */
+      )
+    { 
+      bFound = TRUE;
+      break; 
+    }
+  }
+
+  DPLAYX_ReleaseSemaphore();
+
+  return bFound;
+}
+
+
 /* NOTE: This is potentially not thread safe. You are not guaranteed to end up 
          with the correct string printed in the case where the HRESULT is not
          known. You'll just get the last hr passed in printed. This can change
diff --git a/dlls/dplayx/dplayx_global.h b/dlls/dplayx/dplayx_global.h
index 3310b93..569edb1 100644
--- a/dlls/dplayx/dplayx_global.h
+++ b/dlls/dplayx/dplayx_global.h
@@ -4,18 +4,31 @@
 
 #include "dplay.h"
 
-void DPLAYX_ConstructData(void);
-void DPLAYX_DestructData(void);
+BOOL DPLAYX_ConstructData(void);
+BOOL DPLAYX_DestructData(void);
 
-HRESULT DPLAYX_GetConnectionSettingsA ( DWORD dwAppID, LPVOID lpData, LPDWORD lpdwDataSize );
-HRESULT DPLAYX_GetConnectionSettingsW ( DWORD dwAppID, LPVOID lpData, LPDWORD lpdwDataSize );
+HRESULT DPLAYX_GetConnectionSettingsA ( DWORD dwAppID, 
+                                        LPVOID lpData, 
+                                        LPDWORD lpdwDataSize,
+                                        LPBOOL  lpbSendHaveReadMessage );
+HRESULT DPLAYX_GetConnectionSettingsW ( DWORD dwAppID, 
+                                        LPVOID lpData,
+                                        LPDWORD lpdwDataSize, 
+                                        LPBOOL  lpbSendHaveReadMessage );
 
-HRESULT DPLAYX_SetConnectionSettingsA ( DWORD dwFlags, DWORD dwAppID, LPDPLCONNECTION lpConn );
-HRESULT DPLAYX_SetConnectionSettingsW ( DWORD dwFlags, DWORD dwAppID, LPDPLCONNECTION lpConn );
+HRESULT DPLAYX_SetConnectionSettingsA ( DWORD dwFlags, 
+                                        DWORD dwAppID, 
+                                        LPDPLCONNECTION lpConn );
+HRESULT DPLAYX_SetConnectionSettingsW ( DWORD dwFlags, 
+                                        DWORD dwAppID, 
+                                        LPDPLCONNECTION lpConn );
 
 BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent );
 BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID );
 
+BOOL DPLAYX_WaitForConnectionSettings( BOOL bWait );
+BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void);
+
 LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateLocalSession( UINT* index );
 BOOL DPLAYX_CopyLocalSession( UINT* index, LPDPSESSIONDESC2 lpsd );
 void DPLAYX_SetLocalSession( LPCDPSESSIONDESC2 lpsd );
diff --git a/dlls/dplayx/dplayx_main.c b/dlls/dplayx/dplayx_main.c
index 5d51c9e..25c1a51 100644
--- a/dlls/dplayx/dplayx_main.c
+++ b/dlls/dplayx/dplayx_main.c
@@ -1,7 +1,7 @@
 /* 
  * DPLAYX.DLL LibMain
  *
- * Copyright 1999 - Peter Hunnisett 
+ * Copyright 1999,2000 - Peter Hunnisett 
  *
  * contact <hunnise@nortelnetworks.com>
  */
@@ -17,34 +17,29 @@
 BOOL WINAPI DPLAYX_LibMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
 {
 
-  TRACE( "(%p,0x%08lx,%p) & 0x%08lx\n", hinstDLL, fdwReason, lpvReserved, DPLAYX_dwProcessesAttached );
+  TRACE( "(%u,0x%08lx,%p) & 0x%08lx\n", hinstDLL, fdwReason, lpvReserved, DPLAYX_dwProcessesAttached );
 
   switch ( fdwReason ) 
   {
     case DLL_PROCESS_ATTACH:
     {
 
-      if ( DPLAYX_dwProcessesAttached == 0 )
+      if ( DPLAYX_dwProcessesAttached++ == 0 )
       {
         /* First instance perform construction of global processor data */ 
-        TRACE( "DPLAYX_dwProcessesAttached = 0x%08lx\n", DPLAYX_dwProcessesAttached );
-        DPLAYX_ConstructData();
+        return DPLAYX_ConstructData();
       } 
 
-      DPLAYX_dwProcessesAttached++;
-
       break;
     }
 
     case DLL_PROCESS_DETACH:
     {
 
-      DPLAYX_dwProcessesAttached--;
-     
-      if ( DPLAYX_dwProcessesAttached == 0 )
+      if ( --DPLAYX_dwProcessesAttached == 0 )
       {
-        /* Last instance perform destruction of global processor data */
-        DPLAYX_DestructData(); 
+        /* Last instance performs destruction of global processor data */
+        return DPLAYX_DestructData(); 
       }
  
       break;
diff --git a/dlls/dplayx/dplayx_messages.c b/dlls/dplayx/dplayx_messages.c
new file mode 100644
index 0000000..5fb41e6
--- /dev/null
+++ b/dlls/dplayx/dplayx_messages.c
@@ -0,0 +1,56 @@
+/* DirectPlay & DirectPlayLobby messaging implementation
+ *
+ * Copyright 2000 - Peter Hunnisett
+ *
+ * <presently under construction - contact hunnise@nortelnetworks.com>
+ *
+ */
+
+#include "winbase.h"
+#include "debugtools.h"
+
+#include "dplayx_messages.h"
+
+DEFAULT_DEBUG_CHANNEL(dplay)
+
+
+static DWORD CALLBACK DPLAYX_MSG_ThreadMain( LPVOID lpContext );
+
+/* Create the message reception thread to allow the application to receive
+ * asynchronous message reception
+ */
+DWORD CreateMessageReceptionThread( HANDLE hNotifyEvent )
+{
+  DWORD dwMsgThreadId;
+
+  if( !DuplicateHandle( 0, hNotifyEvent, 0, NULL, 0, FALSE, 0 ) )
+  {
+    ERR( "Unable to duplicate event handle\n" );
+    return 0;
+  }
+
+  /* FIXME: Should most likely store that thread handle */
+  CreateThread( NULL,                  /* Security attribs */
+                0,                     /* Stack */ 
+                DPLAYX_MSG_ThreadMain, /* Msg reception function */
+                (LPVOID)hNotifyEvent,  /* Msg reception function parameter */
+                0,                     /* Flags */
+                &dwMsgThreadId         /* Updated with thread id */
+              );
+ 
+  return dwMsgThreadId;
+}
+static DWORD CALLBACK DPLAYX_MSG_ThreadMain( LPVOID lpContext )
+{
+  HANDLE hMsgEvent = (HANDLE)lpContext;
+
+  for ( ;; )
+  {
+    FIXME( "Ho Hum. Msg thread with nothing to do on handle %u\n", hMsgEvent );
+
+    SleepEx( 10000, FALSE );  /* 10 secs */
+  }
+
+  CloseHandle( hMsgEvent );
+}
+
diff --git a/dlls/dplayx/dplayx_messages.h b/dlls/dplayx/dplayx_messages.h
new file mode 100644
index 0000000..117678f
--- /dev/null
+++ b/dlls/dplayx/dplayx_messages.h
@@ -0,0 +1,10 @@
+
+#ifndef __WINE_DPLAYX_MESSAGES
+#define __WINE_DPLAYX_MESSAGES
+
+#include "windef.h"
+
+DWORD CreateMessageReceptionThread( HANDLE hNotifyEvent );
+
+
+#endif
diff --git a/dlls/dplayx/dplayx_queue.h b/dlls/dplayx/dplayx_queue.h
index 18f4040..471f25c 100644
--- a/dlls/dplayx/dplayx_queue.h
+++ b/dlls/dplayx/dplayx_queue.h
@@ -1,5 +1,4 @@
-
-/* Helper functions for TAILQ functions defined in <sys/queue.h> 
+/* A queue definition based on sys/queue.h TAILQ definitions
  * 
  * Blame any implementation mistakes on Peter Hunnisett
  * <hunnise@nortelnetworks.com>
@@ -8,50 +7,92 @@
 #ifndef __WINE_DPLAYX_QUEUE_H
 #define __WINE_DPLAYX_QUEUE_H
 
-#include <sys/queue.h>
+#define DPQ_INSERT(a,b,c) DPQ_INSERT_IN_TAIL(a,b,c)
 
-/* head - pointer to TAILQ_HEAD struct
- * elm  - how to find the next element
- * field - to be concatenated to rc to compare with fieldToEqual
- * fieldToEqual - The value that we're looking for
- * rc - Variable to put the return code. Same type as (head)->tqh_first
+/*
+ * Tail queue definitions.
  */
-#define TAILQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc )   \
-do {                                                             \
-  (rc) = (head)->tqh_first; /* NULL head? */                     \
-                                                                 \
-  while( rc )                                                    \
-  {                                                              \
-      /* What we're searching for? */                            \
-      if( (rc)->field == (fieldToEqual) )                        \
-      {                                                          \
-        break; /* rc == correct element */                       \
-      }                                                          \
-                                                                 \
-      /* End of list check */                                    \
-      if( ( (rc) = (rc)->elm.tqe_next ) == (head)->tqh_first )   \
-      {                                                          \
-        rc = NULL;                                               \
-        break;                                                   \
-      }                                                          \
-  }                                                              \
+#define DPQ_HEAD(type)                                           \
+struct {                                                         \
+        struct type *lpQHFirst; /* first element */              \
+        struct type **lpQHLast; /* addr of last next element */  \
+}
+
+#define DPQ_ENTRY(type)                                               \
+struct {                                                              \
+        struct type *lpQNext;  /* next element */                     \
+        struct type **lpQPrev; /* address of previous next element */ \
+}
+
+/*
+ * Tail queue functions.
+ */
+#define DPQ_INIT(head)                       \
+do{                                          \
+        (head).lpQHFirst = NULL;             \
+        (head).lpQHLast = &(head).lpQHFirst; \
 } while(0)
 
-/* head - pointer to TAILQ_HEAD struct
+#define DPQ_INSERT_IN_TAIL(head, elm, field)     \
+do {                                             \
+        (elm)->field.lpQNext = NULL;             \
+        (elm)->field.lpQPrev = (head).lpQHLast;  \
+        *(head).lpQHLast = (elm);                \
+        (head).lpQHLast = &(elm)->field.lpQNext; \
+} while(0)
+
+#define DPQ_REMOVE(head, elm, field)                    \
+do {                                                    \
+        if (((elm)->field.lpQNext) != NULL)             \
+                (elm)->field.lpQNext->field.lpQPrev =   \
+                    (elm)->field.lpQPrev;               \
+        else                                            \
+                (head).lpQHLast = (elm)->field.lpQPrev; \
+        *(elm)->field.lpQPrev = (elm)->field.lpQNext;   \
+} while(0)
+
+/* head - pointer to DPQ_HEAD struct
  * elm  - how to find the next element
  * field - to be concatenated to rc to compare with fieldToEqual
  * fieldToEqual - The value that we're looking for
- * rc - Variable to put the return code. Same type as (head)->tqh_first
+ * rc - Variable to put the return code. Same type as (head).lpQHFirst
  */
-#define TAILQ_REMOVE_ENTRY( head, elm, field, fieldToEqual, rc )   \
-do {                                                               \
-  TAILQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc );          \
-                                                                   \
-  /* Was the element found? */                                     \
-  if( rc )                                                         \
-  {                                                                \
-    TAILQ_REMOVE( head, rc, elm );                                 \
-  }                                                                \
+#define DPQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc )   \
+do {                                                           \
+  (rc) = (head).lpQHFirst; /* NULL head? */                    \
+                                                               \
+  while( rc )                                                  \
+  {                                                            \
+      /* What we're searching for? */                          \
+      if( (rc)->field == (fieldToEqual) )                      \
+      {                                                        \
+        break; /* rc == correct element */                     \
+      }                                                        \
+                                                               \
+      /* End of list check */                                  \
+      if( ( (rc) = (rc)->elm.lpQNext ) == (head).lpQHFirst )   \
+      {                                                        \
+        rc = NULL;                                             \
+        break;                                                 \
+      }                                                        \
+  }                                                            \
+} while(0)
+
+/* head - pointer to DPQ_HEAD struct
+ * elm  - how to find the next element
+ * field - to be concatenated to rc to compare with fieldToEqual
+ * fieldToEqual - The value that we're looking for
+ * rc - Variable to put the return code. Same type as (head).lpQHFirst
+ */
+#define DPQ_REMOVE_ENTRY( head, elm, field, fieldToEqual, rc ) \
+do {                                                           \
+  DPQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc );        \
+                                                               \
+  /* Was the element found? */                                 \
+  if( rc )                                                     \
+  {                                                            \
+    DPQ_REMOVE( head, rc, elm );                               \
+  }                                                            \
 } while(0)
 
 #endif /* __WINE_DPLAYX_QUEUE_H */
diff --git a/dlls/dplayx/dplobby.c b/dlls/dplayx/dplobby.c
index b2337de..8507cce 100644
--- a/dlls/dplayx/dplobby.c
+++ b/dlls/dplayx/dplobby.c
@@ -16,9 +16,19 @@
 #include "dplobby.h"
 #include "dpinit.h"
 #include "dplayx_global.h"
+#include "dplayx_messages.h"
 
 DEFAULT_DEBUG_CHANNEL(dplay)
 
+/*****************************************************************************
+ * Predeclare the interface implementation structures
+ */
+typedef struct IDirectPlayLobbyImpl  IDirectPlayLobbyAImpl;
+typedef struct IDirectPlayLobbyImpl  IDirectPlayLobbyWImpl;
+typedef struct IDirectPlayLobby2Impl IDirectPlayLobby2AImpl;
+typedef struct IDirectPlayLobby2Impl IDirectPlayLobby2WImpl;
+typedef struct IDirectPlayLobby3Impl IDirectPlayLobby3AImpl;
+typedef struct IDirectPlayLobby3Impl IDirectPlayLobby3WImpl;
 
 /* Forward declarations for this module helper methods */
 HRESULT DPL_CreateCompoundAddress ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
@@ -32,16 +42,11 @@
 static HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress,
                                 DWORD dwAddressSize, LPVOID lpContext );
 
+static HRESULT WINAPI DPL_ConnectEx( IDirectPlayLobbyAImpl* This, 
+                                     DWORD dwFlags, REFIID riid, 
+                                     LPVOID* lplpDP, IUnknown* pUnk );
 
-/*****************************************************************************
- * Predeclare the interface implementation structures
- */
-typedef struct IDirectPlayLobbyImpl  IDirectPlayLobbyAImpl;
-typedef struct IDirectPlayLobbyImpl  IDirectPlayLobbyWImpl;
-typedef struct IDirectPlayLobby2Impl IDirectPlayLobby2AImpl;
-typedef struct IDirectPlayLobby2Impl IDirectPlayLobby2WImpl;
-typedef struct IDirectPlayLobby3Impl IDirectPlayLobby3AImpl;
-typedef struct IDirectPlayLobby3Impl IDirectPlayLobby3WImpl;
+
 
 /*****************************************************************************
  * IDirectPlayLobby {1,2,3} implementation structure
@@ -65,7 +70,7 @@
 
 typedef struct tagDirectPlayLobbyData
 {
-  HKEY hkCallbackKeyHack;
+  HKEY  hkCallbackKeyHack;
 } DirectPlayLobbyData;
 
 typedef struct tagDirectPlayLobby2Data
@@ -565,11 +570,7 @@
   ULONG refCount;
   ICOM_THIS(IDirectPlayLobbyWImpl,iface);
 
-  EnterCriticalSection( &This->unk->DPL_lock );
-  {
-    refCount = ++(This->unk->ref);
-  }
-  LeaveCriticalSection( &This->unk->DPL_lock );
+  refCount = InterlockedIncrement( &This->unk->ref );
 
   TRACE("ref count incremented to %lu for %p\n", refCount, This );
 
@@ -585,14 +586,9 @@
 ( LPDIRECTPLAYLOBBYA iface )
 {
   ULONG refCount;
-
   ICOM_THIS(IDirectPlayLobbyAImpl,iface);
 
-  EnterCriticalSection( &This->unk->DPL_lock );
-  {
-    refCount = --(This->unk->ref);
-  }
-  LeaveCriticalSection( &This->unk->DPL_lock );
+  refCount = InterlockedDecrement( &This->unk->ref );
 
   TRACE("ref count decremeneted to %lu for %p\n", refCount, This );
 
@@ -618,20 +614,19 @@
  * Returns a IDirectPlay interface.
  *
  */
-static HRESULT WINAPI IDirectPlayLobbyAImpl_Connect
-( LPDIRECTPLAYLOBBYA iface,
-  DWORD dwFlags,
-  LPDIRECTPLAY2A* lplpDP,
+static HRESULT WINAPI DPL_ConnectEx
+( IDirectPlayLobbyAImpl* This, 
+  DWORD     dwFlags,
+  REFIID    riid, 
+  LPVOID*   lplpDP,
   IUnknown* pUnk)
 {
-  ICOM_THIS(IDirectPlayLobbyAImpl,iface);
+  HRESULT         hr;
+  DWORD           dwOpenFlags = 0;
+  DWORD           dwConnSize = 0;
+  LPDPLCONNECTION lpConn;
 
-  LPDIRECTPLAY2A      lpDirectPlay2A;
-  /* LPDIRECTPLAY3A      lpDirectPlay3A; */
-  /* LPDIRECTPLAYLOBBY2A lpDirectPlayLobby2A; */
-  HRESULT             rc;
-
-  FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, dwFlags, lplpDP, pUnk );
+  FIXME("(%p)->(0x%08lx,%p,%p): semi stub\n", This, dwFlags, lplpDP, pUnk );
 
   if( dwFlags || pUnk )
   {
@@ -639,27 +634,66 @@
   }
 
   /* Create the DirectPlay interface */
-  if( ( rc = directPlay_QueryInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) ) != DP_OK )
+  if( ( hr = directPlay_QueryInterface( riid, lplpDP ) ) != DP_OK )
   {
-     ERR("error creating Direct Play 2A interface. Return Code = 0x%lx.\n", rc );
-     return rc;
+     ERR( "error creating interface for %s:%s.\n", 
+          debugstr_guid( riid ), DPLAYX_HresultToString( hr ) );
+     return hr;
   }
 
-  lpDirectPlay2A = *lplpDP;
-
   /* - Need to call IDirectPlay::EnumConnections with the service provider to get that good information
    * - Need to call CreateAddress to create the lpConnection param for IDirectPlay::InitializeConnection
    * - Call IDirectPlay::InitializeConnection
    * - Call IDirectPlay::Open 
    */
-#if 0
-  IDirectPlayLobby_EnumAddress( iface, RunApplicationA_Callback, 
-                                lpConn->lpAddress, lpConn->dwAddressSize, NULL );
-#endif
 
+  /* FIXME: Is it safe/correct to use appID of 0? */
+  hr = IDirectPlayLobby_GetConnectionSettings( (LPDIRECTPLAYLOBBY)This, 
+                                               0, NULL, &dwConnSize ); 
+  if( hr != DPERR_BUFFERTOOSMALL )
+  {
+    return hr;
+  }
+ 
+  lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwConnSize );
 
-  return DP_OK;
+  if( lpConn == NULL )
+  {
+    return DPERR_NOMEMORY;
+  }
 
+  /* FIXME: Is it safe/correct to use appID of 0? */
+  hr = IDirectPlayLobby_GetConnectionSettings( (LPDIRECTPLAYLOBBY)This, 
+                                               0, lpConn, &dwConnSize );
+  if( FAILED( hr ) )
+  {
+    return hr;
+  }
+
+  /* Setup flags to pass into DirectPlay::Open */
+  if( dwFlags & DPCONNECT_RETURNSTATUS )
+  {
+    dwOpenFlags |= DPOPEN_RETURNSTATUS;
+  }
+  dwOpenFlags |= lpConn->dwFlags;
+
+  hr = IDirectPlayX_Open( (*(LPDIRECTPLAY2*)lplpDP), lpConn->lpSessionDesc, 
+                          dwOpenFlags );
+
+  HeapFree( GetProcessHeap(), 0, lpConn );
+
+  return hr;
+}
+
+static HRESULT WINAPI IDirectPlayLobbyAImpl_Connect
+( LPDIRECTPLAYLOBBYA iface,
+  DWORD dwFlags,
+  LPDIRECTPLAY2A* lplpDP,
+  IUnknown* pUnk)
+{
+  ICOM_THIS(IDirectPlayLobbyAImpl,iface);
+  return DPL_ConnectEx( This, dwFlags, &IID_IDirectPlay2A, 
+                        (LPVOID)lplpDP, pUnk );
 }
 
 static HRESULT WINAPI IDirectPlayLobbyWImpl_Connect
@@ -668,29 +702,9 @@
   LPDIRECTPLAY2* lplpDP,
   IUnknown* pUnk)
 {
-  ICOM_THIS(IDirectPlayLobbyWImpl,iface);
-  LPDIRECTPLAY2* directPlay2W;
-  HRESULT        createRC;
-
-  FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, dwFlags, lplpDP, pUnk );
-
-  if( dwFlags || pUnk )
-  {
-     return DPERR_INVALIDPARAMS;
-  }
-
-  /* Create the DirectPlay interface */
-  if( ( createRC = directPlay_QueryInterface( &IID_IDirectPlay2, (LPVOID*)lplpDP ) ) != DP_OK )
-  {
-     ERR("error creating Direct Play 2W interface. Return Code = 0x%lx.\n", createRC );
-     return createRC;
-  } 
-
-  /* This should invoke IDirectPlay3::InitializeConnection IDirectPlay3::Open */  
-  directPlay2W = lplpDP; 
- 
-  return DP_OK;
-
+  ICOM_THIS(IDirectPlayLobbyAImpl,iface); /* Yes cast to A */
+  return DPL_ConnectEx( This, dwFlags, &IID_IDirectPlay2, 
+                        (LPVOID)lplpDP, pUnk );
 }
 
 /********************************************************************
@@ -1099,15 +1113,25 @@
 {
   ICOM_THIS(IDirectPlayLobbyAImpl,iface);
   HRESULT hr; 
+  BOOL    bSendHaveReadSettingsMessage = FALSE;
 
   TRACE("(%p)->(0x%08lx,%p,%p)\n", This, dwAppID, lpData, lpdwDataSize );
 
   EnterCriticalSection( &This->unk->DPL_lock );
 
-  hr = DPLAYX_GetConnectionSettingsA( dwAppID, lpData, lpdwDataSize );
+  hr = DPLAYX_GetConnectionSettingsA( dwAppID, 
+                                      lpData, 
+                                      lpdwDataSize,
+                                      &bSendHaveReadSettingsMessage
+                                    );
 
   LeaveCriticalSection( &This->unk->DPL_lock );
 
+  if( bSendHaveReadSettingsMessage )
+  {
+    FIXME( "Send a DPSYS_CONNECTIONSETTINGSREAD message\n" );
+  }
+
   return hr;
 }
 
@@ -1119,15 +1143,25 @@
 {
   ICOM_THIS(IDirectPlayLobbyWImpl,iface);
   HRESULT hr;
+  BOOL    bSendHaveReadSettingsMessage = FALSE;
 
   TRACE("(%p)->(0x%08lx,%p,%p)\n", This, dwAppID, lpData, lpdwDataSize );
  
   EnterCriticalSection( &This->unk->DPL_lock );
 
-  hr = DPLAYX_GetConnectionSettingsW( dwAppID, lpData, lpdwDataSize );
+  hr = DPLAYX_GetConnectionSettingsW( dwAppID, 
+                                      lpData, 
+                                      lpdwDataSize,
+                                      &bSendHaveReadSettingsMessage
+                                    );
 
   LeaveCriticalSection( &This->unk->DPL_lock );
 
+  if( bSendHaveReadSettingsMessage )
+  {
+    FIXME( "Send a DPSYS_CONNECTIONSETTINGSREAD message\n" );
+  }
+
   return hr;
 }
 
@@ -1274,6 +1308,7 @@
   STARTUPINFOA startupInfo;
   PROCESS_INFORMATION newProcessInfo;
   LPSTR appName;
+  DWORD dwSuspendCount;
 
   TRACE( "(%p)->(0x%08lx,%p,%p,%x)\n", This, dwFlags, lpdwAppID, lpConn, hReceiveEvent );
 
@@ -1282,6 +1317,11 @@
     return DPERR_INVALIDPARAMS;
   }
 
+  if( DPLAYX_AnyLobbiesWaitingForConnSettings() )
+  {
+    FIXME( "Waiting lobby not being handled correctly\n" );
+  }
+
   EnterCriticalSection( &This->unk->DPL_lock );
 
   ZeroMemory( &enumData, sizeof( enumData ) );
@@ -1326,7 +1366,7 @@
                      )
     )
   {
-    FIXME( "Failed to create process for app %s\n", appName );
+    ERR( "Failed to create process for app %s\n", appName );
 
     HeapFree( GetProcessHeap(), 0, appName );
     HeapFree( GetProcessHeap(), 0, enumData.lpszCommandLine );
@@ -1342,25 +1382,35 @@
   /* Reserve this global application id! */
   if( !DPLAYX_CreateLobbyApplication( newProcessInfo.dwProcessId, hReceiveEvent ) )
   {
-    ERR( "Unable to create global application data\n" );
+    ERR( "Unable to create global application data for 0x%08lx\n",
+           newProcessInfo.dwProcessId );
   }
 
   hr = IDirectPlayLobby_SetConnectionSettings( iface, 0, newProcessInfo.dwProcessId, lpConn );
  
   if( hr != DP_OK )
   {
-    FIXME( "SetConnectionSettings failure %s\n", DPLAYX_HresultToString( hr ) );
+    ERR( "SetConnectionSettings failure %s\n", DPLAYX_HresultToString( hr ) );
     return hr;
   }
 
   /* Everything seems to have been set correctly, update the dwAppID */
   *lpdwAppID = newProcessInfo.dwProcessId;
 
-  /* Unsuspend the process */ 
-  ResumeThread( newProcessInfo.dwThreadId );
+  if( hReceiveEvent )
+  {
+    FIXME( "Need to store msg thread id\n" );
+    CreateMessageReceptionThread( hReceiveEvent );
+  } 
 
   LeaveCriticalSection( &This->unk->DPL_lock );
 
+  /* Unsuspend the process - should return the prev suspension count */ 
+  if( ( dwSuspendCount = ResumeThread( newProcessInfo.hThread ) ) != 1 )
+  {
+    ERR( "ResumeThread failed with 0x%08lx\n", dwSuspendCount );
+  }
+
   return DP_OK;
 }
 
@@ -1425,6 +1475,17 @@
 
   hr = DPLAYX_SetConnectionSettingsW( dwFlags, dwAppID, lpConn );
 
+  /* FIXME: Don't think that this is supposed to fail, but the docuementation
+            is somewhat sketchy. I'll try creating a lobby application
+            for this... */
+  if( hr == DPERR_NOTLOBBIED )
+  {
+    FIXME( "Unlobbied app setting connections. Is this correct behavior?\n" );
+    dwAppID = GetCurrentProcessId();
+    DPLAYX_CreateLobbyApplication( dwAppID, 0 );
+    hr = DPLAYX_SetConnectionSettingsW( dwFlags, dwAppID, lpConn );
+  }
+
   LeaveCriticalSection( &This->unk->DPL_lock );
 
   return hr;
@@ -1445,6 +1506,17 @@
 
   hr = DPLAYX_SetConnectionSettingsA( dwFlags, dwAppID, lpConn );
 
+  /* FIXME: Don't think that this is supposed to fail, but the docuementation
+            is somewhat sketchy. I'll try creating a lobby application
+            for this... */
+  if( hr == DPERR_NOTLOBBIED )
+  {
+    FIXME( "Unlobbied app setting connections. Is this correct behavior?\n" );
+    dwAppID = GetCurrentProcessId();
+    DPLAYX_CreateLobbyApplication( dwAppID, 0 );
+    hr = DPLAYX_SetConnectionSettingsA( dwFlags, dwAppID, lpConn );
+  }
+
   LeaveCriticalSection( &This->unk->DPL_lock );
 
   return hr;
@@ -1477,12 +1549,6 @@
 
 
 /* DPL 2 methods */
-
-/********************************************************************
- *
- * Registers an event that will be set when a lobby message is received.
- *
- */
 static HRESULT WINAPI IDirectPlayLobby2WImpl_CreateCompoundAddress
 ( LPDIRECTPLAYLOBBY2 iface,
   LPCDPCOMPOUNDADDRESSELEMENT lpElements,
@@ -1680,17 +1746,19 @@
 /* DPL 3 methods */
 
 static HRESULT WINAPI IDirectPlayLobby3WImpl_ConnectEx
-( LPDIRECTPLAYLOBBY3 iface, DWORD dwFlags, REFIID riid, LPVOID* lplpDP, IUnknown* pUnk )
+( LPDIRECTPLAYLOBBY3 iface, DWORD dwFlags, REFIID riid, 
+  LPVOID* lplpDP, IUnknown* pUnk )
 {
-  FIXME(":stub\n");
-  return DP_OK;
+  ICOM_THIS( IDirectPlayLobbyAImpl, iface );
+  return DPL_ConnectEx( This, dwFlags, riid, lplpDP, pUnk );
 }
 
 static HRESULT WINAPI IDirectPlayLobby3AImpl_ConnectEx
-( LPDIRECTPLAYLOBBY3A iface, DWORD dwFlags, REFIID riid, LPVOID* lplpDP, IUnknown* pUnk )
+( LPDIRECTPLAYLOBBY3A iface, DWORD dwFlags, REFIID riid, 
+  LPVOID* lplpDP, IUnknown* pUnk )
 {
-  FIXME(":stub\n");
-  return DP_OK;
+  ICOM_THIS( IDirectPlayLobbyAImpl, iface );
+  return DPL_ConnectEx( This, dwFlags, riid, lplpDP, pUnk );
 }
 
 static HRESULT WINAPI IDirectPlayLobby3WImpl_RegisterApplication
@@ -1724,15 +1792,35 @@
 static HRESULT WINAPI IDirectPlayLobby3WImpl_WaitForConnectionSettings
 ( LPDIRECTPLAYLOBBY3 iface, DWORD dwFlags )
 {
-  FIXME(":stub\n");
-  return DP_OK;
+  HRESULT hr         = DP_OK;
+  BOOL    bStartWait = (dwFlags & DPLWAIT_CANCEL) ? FALSE : TRUE;
+
+  TRACE( "(%p)->(0x%08lx)\n", iface, dwFlags );
+
+  if( DPLAYX_WaitForConnectionSettings( bStartWait ) )
+  {
+    /* FIXME: What is the correct error return code? */
+    hr = DPERR_NOTLOBBIED; 
+  }
+
+  return hr;
 }
 
 static HRESULT WINAPI IDirectPlayLobby3AImpl_WaitForConnectionSettings
 ( LPDIRECTPLAYLOBBY3A iface, DWORD dwFlags )
 {
-  FIXME(":stub\n");
-  return DP_OK;
+  HRESULT hr         = DP_OK;
+  BOOL    bStartWait = (dwFlags & DPLWAIT_CANCEL) ? FALSE : TRUE;
+
+  TRACE( "(%p)->(0x%08lx)\n", iface, dwFlags );
+
+  if( DPLAYX_WaitForConnectionSettings( bStartWait ) )
+  {
+    /* FIXME: What is the correct error return code? */
+    hr = DPERR_NOTLOBBIED;
+  }
+
+  return hr;
 }