ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

dplay.c
Go to the documentation of this file.
00001 /* Direct Play 2,3,4 Implementation
00002  *
00003  * Copyright 1998,1999,2000,2001 - Peter Hunnisett
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2.1 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with this library; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #include "config.h"
00021 #include "wine/port.h"
00022 
00023 #include <stdarg.h>
00024 #include <string.h>
00025 
00026 #define NONAMELESSUNION
00027 #define NONAMELESSSTRUCT
00028 #include "windef.h"
00029 #include "winerror.h"
00030 #include "winbase.h"
00031 #include "winnt.h"
00032 #include "winreg.h"
00033 #include "winnls.h"
00034 #include "wine/unicode.h"
00035 #include "wine/debug.h"
00036 
00037 #include "dpinit.h"
00038 #include "dplayx_global.h"
00039 #include "name_server.h"
00040 #include "dplayx_queue.h"
00041 #include "dplaysp.h"
00042 #include "dplay_global.h"
00043 
00044 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
00045 
00046 /* FIXME: Should this be externed? */
00047 extern HRESULT DPL_CreateCompoundAddress
00048 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
00049   LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
00050 
00051 
00052 /* Local function prototypes */
00053 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
00054 static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
00055                                      LPDPNAME lpName, DWORD dwFlags,
00056                                      HANDLE hEvent, BOOL bAnsi );
00057 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi );
00058 static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
00059                               LPVOID lpData, DWORD dwDataSize );
00060 
00061 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, LPDPID lpid,
00062                                    LPDPNAME lpName, DWORD dwFlags,
00063                                    DPID idParent, BOOL bAnsi );
00064 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
00065                              LPVOID lpData, DWORD dwDataSize );
00066 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
00067 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
00068 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
00069                                                   DWORD dwPlayerType,
00070                                                   LPCDPNAME lpName,
00071                                                   DWORD dwFlags,
00072                                                   LPVOID lpContext );
00073 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
00074 static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
00075                                             LPCDPNAME lpName, DWORD dwFlags,
00076                                             LPVOID lpContext );
00077 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
00078 
00079 /* Forward declarations of virtual tables */
00080 static const IDirectPlay2Vtbl directPlay2AVT;
00081 static const IDirectPlay3Vtbl directPlay3AVT;
00082 static const IDirectPlay4Vtbl directPlay4AVT;
00083 
00084 static const IDirectPlay2Vtbl directPlay2WVT;
00085 static const IDirectPlay3Vtbl directPlay3WVT;
00086 static const IDirectPlay4Vtbl directPlay4WVT;
00087 
00088 /* Helper methods for player/group interfaces */
00089 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
00090           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
00091             DPID idPlayer, BOOL bAnsi );
00092 static HRESULT WINAPI DP_IF_CreatePlayer
00093           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
00094             LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
00095             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
00096 static HRESULT WINAPI DP_IF_DestroyGroup
00097           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
00098 static HRESULT WINAPI DP_IF_DestroyPlayer
00099           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
00100 static HRESULT WINAPI DP_IF_EnumGroupPlayers
00101           ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
00102             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
00103             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
00104 static HRESULT WINAPI DP_IF_EnumGroups
00105           ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
00106             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
00107             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
00108 static HRESULT WINAPI DP_IF_EnumPlayers
00109           ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
00110             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
00111             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
00112 static HRESULT WINAPI DP_IF_GetGroupData
00113           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
00114             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
00115 static HRESULT WINAPI DP_IF_GetGroupName
00116           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
00117             LPDWORD lpdwDataSize, BOOL bAnsi );
00118 static HRESULT WINAPI DP_IF_GetPlayerData
00119           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
00120             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
00121 static HRESULT WINAPI DP_IF_GetPlayerName
00122           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
00123             LPDWORD lpdwDataSize, BOOL bAnsi );
00124 static HRESULT WINAPI DP_IF_SetGroupName
00125           ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
00126             DWORD dwFlags, BOOL bAnsi );
00127 static HRESULT WINAPI DP_IF_SetPlayerData
00128           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
00129             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
00130 static HRESULT WINAPI DP_IF_SetPlayerName
00131           ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
00132             DWORD dwFlags, BOOL bAnsi );
00133 static HRESULT WINAPI DP_IF_AddGroupToGroup
00134           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
00135 static HRESULT WINAPI DP_IF_CreateGroup
00136           ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
00137             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
00138             DWORD dwFlags, BOOL bAnsi );
00139 static HRESULT WINAPI DP_IF_CreateGroupInGroup
00140           ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
00141             LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
00142             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
00143 static HRESULT WINAPI DP_IF_AddPlayerToGroup
00144           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
00145             DPID idPlayer, BOOL bAnsi );
00146 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
00147           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
00148 static HRESULT WINAPI DP_SetSessionDesc
00149           ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
00150             DWORD dwFlags, BOOL bInitial, BOOL bAnsi  );
00151 static HRESULT WINAPI DP_SecureOpen
00152           ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
00153             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
00154             BOOL bAnsi );
00155 static HRESULT WINAPI DP_SendEx
00156           ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
00157             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
00158             LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
00159 static HRESULT WINAPI DP_IF_Receive
00160           ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
00161             DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
00162 static HRESULT WINAPI DP_IF_GetMessageQueue
00163           ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
00164             LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
00165 static HRESULT WINAPI DP_SP_SendEx
00166           ( IDirectPlay2Impl* This, DWORD dwFlags,
00167             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
00168             LPVOID lpContext, LPDWORD lpdwMsgID );
00169 static HRESULT WINAPI DP_IF_SetGroupData
00170           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
00171             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
00172 static HRESULT WINAPI DP_IF_GetPlayerCaps
00173           ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
00174             DWORD dwFlags );
00175 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
00176 static HRESULT WINAPI DP_IF_CancelMessage
00177           ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
00178             DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
00179 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
00180           ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
00181             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
00182             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
00183 static HRESULT WINAPI DP_IF_GetGroupParent
00184           ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
00185             BOOL bAnsi );
00186 static HRESULT WINAPI DP_IF_GetCaps
00187           ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
00188 static HRESULT WINAPI DP_IF_EnumSessions
00189           ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
00190             LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
00191             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
00192 static HRESULT WINAPI DP_IF_InitializeConnection
00193           ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
00194 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
00195     LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
00196     DWORD dwFlags, LPVOID lpContext );
00197 static BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
00198                                            LPDWORD lpdwBufSize );
00199 
00200 
00201 
00202 static inline DPID DP_NextObjectId(void);
00203 static DPID DP_GetRemoteNextObjectId(void);
00204 
00205 
00206 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
00207                                 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
00208 
00209 
00210 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
00211 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
00212 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
00213 
00214 
00215 
00216 
00217 
00218 
00219 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
00220 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
00221                                                  we don't have to change much */
00222 #define DPID_NAME_SERVER 0x19a9d65b  /* Don't ask me why */
00223 
00224 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
00225 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
00226 
00227 /* Strip out all dwFlags values for CREATEPLAYER msg */
00228 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
00229 
00230 static LONG kludgePlayerGroupId = 1000;
00231 
00232 /* ------------------------------------------------------------------ */
00233 
00234 
00235 static BOOL DP_CreateIUnknown( LPVOID lpDP )
00236 {
00237   IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
00238 
00239   This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
00240   if ( This->unk == NULL )
00241   {
00242     return FALSE;
00243   }
00244 
00245   InitializeCriticalSection( &This->unk->DP_lock );
00246 
00247   return TRUE;
00248 }
00249 
00250 static BOOL DP_DestroyIUnknown( LPVOID lpDP )
00251 {
00252   IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
00253 
00254   DeleteCriticalSection( &This->unk->DP_lock );
00255   HeapFree( GetProcessHeap(), 0, This->unk );
00256 
00257   return TRUE;
00258 }
00259 
00260 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
00261 {
00262   IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
00263 
00264   This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
00265   if ( This->dp2 == NULL )
00266   {
00267     return FALSE;
00268   }
00269 
00270   This->dp2->bConnectionOpen = FALSE;
00271 
00272   This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
00273 
00274   This->dp2->bHostInterface = FALSE;
00275 
00276   DPQ_INIT(This->dp2->receiveMsgs);
00277   DPQ_INIT(This->dp2->sendMsgs);
00278   DPQ_INIT(This->dp2->replysExpected);
00279 
00280   if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
00281   {
00282     /* FIXME: Memory leak */
00283     return FALSE;
00284   }
00285 
00286   /* Provide an initial session desc with nothing in it */
00287   This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
00288                                         HEAP_ZERO_MEMORY,
00289                                         sizeof( *This->dp2->lpSessionDesc ) );
00290   if( This->dp2->lpSessionDesc == NULL )
00291   {
00292     /* FIXME: Memory leak */
00293     return FALSE;
00294   }
00295   This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
00296 
00297   /* We are emulating a dp 6 implementation */
00298   This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
00299 
00300   This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
00301                                       sizeof( *This->dp2->spData.lpCB ) );
00302   This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
00303   This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
00304 
00305   /* This is the pointer to the service provider */
00306   if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
00307                                     (LPVOID*)&This->dp2->spData.lpISP, This ) )
00308     )
00309   {
00310     /* FIXME: Memory leak */
00311     return FALSE;
00312   }
00313 
00314   /* Setup lobby provider information */
00315   This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
00316   This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
00317                                          sizeof( *This->dp2->dplspData.lpCB ) );
00318   This->dp2->dplspData.lpCB->dwSize = sizeof(  *This->dp2->dplspData.lpCB );
00319 
00320   if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
00321                                      (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
00322     )
00323   {
00324     /* FIXME: Memory leak */
00325     return FALSE;
00326   }
00327 
00328   return TRUE;
00329 }
00330 
00331 /* Definition of the global function in dplayx_queue.h. #
00332  * FIXME: Would it be better to have a dplayx_queue.c for this function? */
00333 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
00334 {
00335   HeapFree( GetProcessHeap(), 0, elem );
00336 }
00337 
00338 /* Function to delete the list of groups with this interface. Needs to
00339  * delete the group and player lists associated with this group as well
00340  * as the group data associated with this group. It should not delete
00341  * player data as that is shared with the top player list and will be
00342  * deleted with that.
00343  */
00344 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList );
00345 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList )
00346 {
00347   DPQ_DELETEQ( elem->lpGData->groups, groups,
00348                lpGroupList, cbDeleteElemFromHeap );
00349   DPQ_DELETEQ( elem->lpGData->players, players,
00350                lpPlayerList, cbDeleteElemFromHeap );
00351   HeapFree( GetProcessHeap(), 0, elem->lpGData );
00352   HeapFree( GetProcessHeap(), 0, elem );
00353 }
00354 
00355 /* Function to delete the list of players with this interface. Needs to
00356  * delete the player data for all players as well.
00357  */
00358 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList );
00359 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList )
00360 {
00361   HeapFree( GetProcessHeap(), 0, elem->lpPData );
00362   HeapFree( GetProcessHeap(), 0, elem );
00363 }
00364 
00365 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
00366 {
00367   IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
00368 
00369   if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
00370   {
00371     TerminateThread( This->dp2->hEnumSessionThread, 0 );
00372     CloseHandle( This->dp2->hEnumSessionThread );
00373   }
00374 
00375   /* Finish with the SP - have it shutdown */
00376   if( This->dp2->spData.lpCB->ShutdownEx )
00377   {
00378     DPSP_SHUTDOWNDATA data;
00379 
00380     TRACE( "Calling SP ShutdownEx\n" );
00381 
00382     data.lpISP = This->dp2->spData.lpISP;
00383 
00384     (*This->dp2->spData.lpCB->ShutdownEx)( &data );
00385   }
00386   else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
00387   {
00388     TRACE( "Calling obsolete SP Shutdown\n" );
00389     (*This->dp2->spData.lpCB->Shutdown)();
00390   }
00391 
00392   /* Unload the SP (if it exists) */
00393   if( This->dp2->hServiceProvider != 0 )
00394   {
00395     FreeLibrary( This->dp2->hServiceProvider );
00396   }
00397 
00398   /* Unload the Lobby Provider (if it exists) */
00399   if( This->dp2->hDPLobbyProvider != 0 )
00400   {
00401     FreeLibrary( This->dp2->hDPLobbyProvider );
00402   }
00403 
00404 #if 0
00405   DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
00406   DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem );
00407 #endif
00408 
00409   /* FIXME: Need to delete receive and send msgs queue contents */
00410 
00411   NS_DeleteSessionCache( This->dp2->lpNameServerData );
00412 
00413   HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
00414 
00415   IDirectPlaySP_Release( This->dp2->spData.lpISP );
00416 
00417   /* Delete the contents */
00418   HeapFree( GetProcessHeap(), 0, This->dp2 );
00419 
00420   return TRUE;
00421 }
00422 
00423 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
00424 {
00425   IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
00426 
00427   This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
00428   if ( This->dp3 == NULL )
00429   {
00430     return FALSE;
00431   }
00432 
00433   return TRUE;
00434 }
00435 
00436 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
00437 {
00438   IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
00439 
00440   /* Delete the contents */
00441   HeapFree( GetProcessHeap(), 0, This->dp3 );
00442 
00443   return TRUE;
00444 }
00445 
00446 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
00447 {
00448   IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)lpDP;
00449 
00450   This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
00451   if ( This->dp4 == NULL )
00452   {
00453     return FALSE;
00454   }
00455 
00456   return TRUE;
00457 }
00458 
00459 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
00460 {
00461   IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
00462 
00463   /* Delete the contents */
00464   HeapFree( GetProcessHeap(), 0, This->dp4 );
00465 
00466   return TRUE;
00467 }
00468 
00469 
00470 /* Create a new interface */
00471 extern
00472 HRESULT DP_CreateInterface
00473          ( REFIID riid, LPVOID* ppvObj )
00474 {
00475   TRACE( " for %s\n", debugstr_guid( riid ) );
00476 
00477   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
00478                        sizeof( IDirectPlay2Impl ) );
00479 
00480   if( *ppvObj == NULL )
00481   {
00482     return DPERR_OUTOFMEMORY;
00483   }
00484 
00485   if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
00486   {
00487     IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
00488     This->lpVtbl = &directPlay2WVT;
00489   }
00490   else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
00491   {
00492     IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
00493     This->lpVtbl = &directPlay2AVT;
00494   }
00495   else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
00496   {
00497     IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
00498     This->lpVtbl = &directPlay3WVT;
00499   }
00500   else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
00501   {
00502     IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
00503     This->lpVtbl = &directPlay3AVT;
00504   }
00505   else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
00506   {
00507     IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
00508     This->lpVtbl = &directPlay4WVT;
00509   }
00510   else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
00511   {
00512     IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
00513     This->lpVtbl = &directPlay4AVT;
00514   }
00515   else
00516   {
00517     /* Unsupported interface */
00518     HeapFree( GetProcessHeap(), 0, *ppvObj );
00519     *ppvObj = NULL;
00520 
00521     return E_NOINTERFACE;
00522   }
00523 
00524   /* Initialize it */
00525   if ( DP_CreateIUnknown( *ppvObj ) &&
00526        DP_CreateDirectPlay2( *ppvObj ) &&
00527        DP_CreateDirectPlay3( *ppvObj ) &&
00528        DP_CreateDirectPlay4( *ppvObj )
00529      )
00530   {
00531     IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
00532 
00533     return S_OK;
00534   }
00535 
00536   /* Initialize failed, destroy it */
00537   DP_DestroyDirectPlay4( *ppvObj );
00538   DP_DestroyDirectPlay3( *ppvObj );
00539   DP_DestroyDirectPlay2( *ppvObj );
00540   DP_DestroyIUnknown( *ppvObj );
00541 
00542   HeapFree( GetProcessHeap(), 0, *ppvObj );
00543 
00544   *ppvObj = NULL;
00545   return DPERR_NOMEMORY;
00546 }
00547 
00548 
00549 /* Direct Play methods */
00550 
00551 /* Shared between all dplay types */
00552 static HRESULT WINAPI DP_QueryInterface
00553          ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
00554 {
00555   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
00556   TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
00557 
00558   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
00559                        sizeof( *This ) );
00560 
00561   if( *ppvObj == NULL )
00562   {
00563     return DPERR_OUTOFMEMORY;
00564   }
00565 
00566   CopyMemory( *ppvObj, This, sizeof( *This )  );
00567   (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
00568 
00569   if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
00570   {
00571     IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
00572     This->lpVtbl = &directPlay2WVT;
00573   }
00574   else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
00575   {
00576     IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
00577     This->lpVtbl = &directPlay2AVT;
00578   }
00579   else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
00580   {
00581     IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
00582     This->lpVtbl = &directPlay3WVT;
00583   }
00584   else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
00585   {
00586     IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
00587     This->lpVtbl = &directPlay3AVT;
00588   }
00589   else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
00590   {
00591     IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
00592     This->lpVtbl = &directPlay4WVT;
00593   }
00594   else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
00595   {
00596     IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
00597     This->lpVtbl = &directPlay4AVT;
00598   }
00599   else
00600   {
00601     /* Unsupported interface */
00602     HeapFree( GetProcessHeap(), 0, *ppvObj );
00603     *ppvObj = NULL;
00604 
00605     return E_NOINTERFACE;
00606   }
00607 
00608   IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
00609 
00610   return S_OK;
00611 }
00612 
00613 /* Shared between all dplay types */
00614 static ULONG WINAPI DP_AddRef
00615          ( LPDIRECTPLAY3 iface )
00616 {
00617   ULONG ulInterfaceRefCount, ulObjRefCount;
00618   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
00619 
00620   ulObjRefCount       = InterlockedIncrement( &This->unk->ulObjRef );
00621   ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
00622 
00623   TRACE( "ref count incremented to %lu:%lu for %p\n",
00624          ulInterfaceRefCount, ulObjRefCount, This );
00625 
00626   return ulObjRefCount;
00627 }
00628 
00629 static ULONG WINAPI DP_Release
00630 ( LPDIRECTPLAY3 iface )
00631 {
00632   ULONG ulInterfaceRefCount, ulObjRefCount;
00633 
00634   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
00635 
00636   ulObjRefCount       = InterlockedDecrement( &This->unk->ulObjRef );
00637   ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
00638 
00639   TRACE( "ref count decremented to %lu:%lu for %p\n",
00640          ulInterfaceRefCount, ulObjRefCount, This );
00641 
00642   /* Deallocate if this is the last reference to the object */
00643   if( ulObjRefCount == 0 )
00644   {
00645      /* If we're destroying the object, this must be the last ref
00646         of the last interface */
00647      DP_DestroyDirectPlay4( This );
00648      DP_DestroyDirectPlay3( This );
00649      DP_DestroyDirectPlay2( This );
00650      DP_DestroyIUnknown( This );
00651   }
00652 
00653   /* Deallocate the interface */
00654   if( ulInterfaceRefCount == 0 )
00655   {
00656     HeapFree( GetProcessHeap(), 0, This );
00657   }
00658 
00659   return ulObjRefCount;
00660 }
00661 
00662 static inline DPID DP_NextObjectId(void)
00663 {
00664   return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
00665 }
00666 
00667 /* *lplpReply will be non NULL iff there is something to reply */
00668 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
00669                           DWORD  dwMessageBodySize, LPCVOID lpcMessageHeader,
00670                           WORD wCommandId, WORD wVersion,
00671                           LPVOID* lplpReply, LPDWORD lpdwMsgSize )
00672 {
00673   TRACE( "(%p)->(%p,0x%08lx,%p,%u,%u)\n",
00674          This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
00675          wVersion );
00676 
00677   switch( wCommandId )
00678   {
00679     /* Name server needs to handle this request */
00680     case DPMSGCMD_ENUMSESSIONSREQUEST:
00681     {
00682       /* Reply expected */
00683       NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
00684 
00685       break;
00686     }
00687 
00688     /* Name server needs to handle this request */
00689     case DPMSGCMD_ENUMSESSIONSREPLY:
00690     {
00691       /* No reply expected */
00692       NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
00693                                         This->dp2->spData.dwSPHeaderSize,
00694                                         (LPDPMSG_ENUMSESSIONSREPLY)lpcMessageBody,
00695                                         This->dp2->lpNameServerData );
00696       break;
00697     }
00698 
00699     case DPMSGCMD_REQUESTNEWPLAYERID:
00700     {
00701       LPCDPMSG_REQUESTNEWPLAYERID lpcMsg =
00702         (LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody;
00703 
00704       LPDPMSG_NEWPLAYERIDREPLY lpReply;
00705 
00706       *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
00707 
00708       *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
00709 
00710       FIXME( "Ignoring dwFlags 0x%08lx in request msg\n",
00711              lpcMsg->dwFlags );
00712 
00713       /* Setup the reply */
00714       lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
00715                                             This->dp2->spData.dwSPHeaderSize );
00716 
00717       lpReply->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG;
00718       lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
00719       lpReply->envelope.wVersion   = DPMSGVER_DP6;
00720 
00721       lpReply->dpidNewPlayerId = DP_NextObjectId();
00722 
00723       TRACE( "Allocating new playerid 0x%08lx from remote request\n",
00724              lpReply->dpidNewPlayerId );
00725 
00726       break;
00727     }
00728 
00729     case DPMSGCMD_GETNAMETABLEREPLY:
00730     case DPMSGCMD_NEWPLAYERIDREPLY:
00731     {
00732 
00733 #if 0
00734       if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
00735         DebugBreak();
00736 #endif
00737       DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
00738 
00739       break;
00740     }
00741 
00742 #if 1
00743     case DPMSGCMD_JUSTENVELOPE:
00744     {
00745       TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08lx\n", lpcMessageHeader, ((LPDWORD)lpcMessageHeader)[1] );
00746       NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
00747       DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
00748     }
00749 #endif
00750 
00751     case DPMSGCMD_FORWARDADDPLAYER:
00752     {
00753 #if 0
00754       DebugBreak();
00755 #endif
00756 #if 1
00757     TRACE( "Sending message to self to get my addr\n" );
00758     DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
00759 #endif
00760       break;
00761     }
00762 
00763     case DPMSGCMD_FORWARDADDPLAYERNACK:
00764     {
00765       DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
00766       break;
00767     }
00768 
00769     default:
00770     {
00771       FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
00772       DebugBreak();
00773       break;
00774     }
00775   }
00776 
00777   /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
00778 
00779   return DP_OK;
00780 }
00781 
00782 
00783 static HRESULT WINAPI DP_IF_AddPlayerToGroup
00784           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
00785             DPID idPlayer, BOOL bAnsi )
00786 {
00787   lpGroupData  lpGData;
00788   lpPlayerList lpPList;
00789   lpPlayerList lpNewPList;
00790 
00791   TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n",
00792          This, lpMsgHdr, idGroup, idPlayer, bAnsi );
00793 
00794   /* Find the group */
00795   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
00796   {
00797     return DPERR_INVALIDGROUP;
00798   }
00799 
00800   /* Find the player */
00801   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
00802   {
00803     return DPERR_INVALIDPLAYER;
00804   }
00805 
00806   /* Create a player list (ie "shortcut" ) */
00807   lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
00808   if( lpNewPList == NULL )
00809   {
00810     return DPERR_CANTADDPLAYER;
00811   }
00812 
00813   /* Add the shortcut */
00814   lpPList->lpPData->uRef++;
00815   lpNewPList->lpPData = lpPList->lpPData;
00816 
00817   /* Add the player to the list of players for this group */
00818   DPQ_INSERT(lpGData->players,lpNewPList,players);
00819 
00820   /* Let the SP know that we've added a player to the group */
00821   if( This->dp2->spData.lpCB->AddPlayerToGroup )
00822   {
00823     DPSP_ADDPLAYERTOGROUPDATA data;
00824 
00825     TRACE( "Calling SP AddPlayerToGroup\n" );
00826 
00827     data.idPlayer = idPlayer;
00828     data.idGroup  = idGroup;
00829     data.lpISP    = This->dp2->spData.lpISP;
00830 
00831     (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
00832   }
00833 
00834   /* Inform all other peers of the addition of player to the group. If there are
00835    * no peers keep this event quiet.
00836    * Also, if this event was the result of another machine sending it to us,
00837    * don't bother rebroadcasting it.
00838    */
00839   if( ( lpMsgHdr == NULL ) &&
00840       This->dp2->lpSessionDesc &&
00841       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
00842   {
00843     DPMSG_ADDPLAYERTOGROUP msg;
00844     msg.dwType = DPSYS_ADDPLAYERTOGROUP;
00845 
00846     msg.dpIdGroup  = idGroup;
00847     msg.dpIdPlayer = idPlayer;
00848 
00849     /* FIXME: Correct to just use send effectively? */
00850     /* FIXME: Should size include data w/ message or just message "header" */
00851     /* FIXME: Check return code */
00852     DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),               0, 0, NULL, NULL, bAnsi );
00853   }
00854 
00855   return DP_OK;
00856 }
00857 
00858 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
00859           ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
00860 {
00861   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
00862   return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
00863 }
00864 
00865 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
00866           ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
00867 {
00868   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
00869   return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
00870 }
00871 
00872 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
00873 {
00874   HRESULT hr = DP_OK;
00875 
00876   TRACE("(%p)->(%u)\n", This, bAnsi );
00877 
00878   /* FIXME: Need to find a new host I assume (how?) */
00879   /* FIXME: Need to destroy all local groups */
00880   /* FIXME: Need to migrate all remotely visible players to the new host */
00881 
00882   /* Invoke the SP callback to inform of session close */
00883   if( This->dp2->spData.lpCB->CloseEx )
00884   {
00885     DPSP_CLOSEDATA data;
00886 
00887     TRACE( "Calling SP CloseEx\n" );
00888 
00889     data.lpISP = This->dp2->spData.lpISP;
00890 
00891     hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
00892 
00893   }
00894   else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
00895   {
00896     TRACE( "Calling SP Close (obsolete interface)\n" );
00897 
00898     hr = (*This->dp2->spData.lpCB->Close)();
00899   }
00900 
00901   return hr;
00902 }
00903 
00904 static HRESULT WINAPI DirectPlay2AImpl_Close
00905           ( LPDIRECTPLAY2A iface )
00906 {
00907   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
00908   return DP_IF_Close( This, TRUE );
00909 }
00910 
00911 static HRESULT WINAPI DirectPlay2WImpl_Close
00912           ( LPDIRECTPLAY2 iface )
00913 {
00914   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
00915   return DP_IF_Close( This, FALSE );
00916 }
00917 
00918 static
00919 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, LPDPID lpid,
00920                             LPDPNAME lpName, DWORD dwFlags,
00921                             DPID idParent, BOOL bAnsi )
00922 {
00923   lpGroupData lpGData;
00924 
00925   /* Allocate the new space and add to end of high level group list */
00926   lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
00927 
00928   if( lpGData == NULL )
00929   {
00930     return NULL;
00931   }
00932 
00933   DPQ_INIT(lpGData->groups);
00934   DPQ_INIT(lpGData->players);
00935 
00936   /* Set the desired player ID - no sanity checking to see if it exists */
00937   lpGData->dpid = *lpid;
00938 
00939   DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
00940 
00941   /* FIXME: Should we check that the parent exists? */
00942   lpGData->parent  = idParent;
00943 
00944   /* FIXME: Should we validate the dwFlags? */
00945   lpGData->dwFlags = dwFlags;
00946 
00947   TRACE( "Created group id 0x%08lx\n", *lpid );
00948 
00949   return lpGData;
00950 }
00951 
00952 /* This method assumes that all links to it are already deleted */
00953 static void
00954 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
00955 {
00956   lpGroupList lpGList;
00957 
00958   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
00959 
00960   DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
00961 
00962   if( lpGList == NULL )
00963   {
00964     ERR( "DPID 0x%08lx not found\n", dpid );
00965     return;
00966   }
00967 
00968   if( --(lpGList->lpGData->uRef) )
00969   {
00970     FIXME( "Why is this not the last reference to group?\n" );
00971     DebugBreak();
00972   }
00973 
00974   /* Delete player */
00975   DP_DeleteDPNameStruct( &lpGList->lpGData->name );
00976   HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
00977 
00978   /* Remove and Delete Player List object */
00979   HeapFree( GetProcessHeap(), 0, lpGList );
00980 
00981 }
00982 
00983 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
00984 {
00985   lpGroupList lpGroups;
00986 
00987   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
00988 
00989   if( dpid == DPID_SYSTEM_GROUP )
00990   {
00991     return This->dp2->lpSysGroup;
00992   }
00993   else
00994   {
00995     DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
00996   }
00997 
00998   if( lpGroups == NULL )
00999   {
01000     return NULL;
01001   }
01002 
01003   return lpGroups->lpGData;
01004 }
01005 
01006 static HRESULT WINAPI DP_IF_CreateGroup
01007           ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
01008             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
01009             DWORD dwFlags, BOOL bAnsi )
01010 {
01011   lpGroupData lpGData;
01012 
01013   TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
01014          This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
01015          dwFlags, bAnsi );
01016 
01017   /* If the name is not specified, we must provide one */
01018   if( DPID_UNKNOWN == *lpidGroup )
01019   {
01020     /* If we are the name server, we decide on the group ids. If not, we
01021      * must ask for one before attempting a creation.
01022      */
01023     if( This->dp2->bHostInterface )
01024     {
01025       *lpidGroup = DP_NextObjectId();
01026     }
01027     else
01028     {
01029       *lpidGroup = DP_GetRemoteNextObjectId();
01030     }
01031   }
01032 
01033   lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
01034                             DPID_NOPARENT_GROUP, bAnsi );
01035 
01036   if( lpGData == NULL )
01037   {
01038     return DPERR_CANTADDPLAYER; /* yes player not group */
01039   }
01040 
01041   if( DPID_SYSTEM_GROUP == *lpidGroup )
01042   {
01043     This->dp2->lpSysGroup = lpGData;
01044     TRACE( "Inserting system group\n" );
01045   }
01046   else
01047   {
01048     /* Insert into the system group */
01049     lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
01050     lpGroup->lpGData = lpGData;
01051 
01052     DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
01053   }
01054 
01055   /* Something is now referencing this data */
01056   lpGData->uRef++;
01057 
01058   /* Set all the important stuff for the group */
01059   DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
01060 
01061   /* FIXME: We should only create the system group if GetCaps returns
01062    *        DPCAPS_GROUPOPTIMIZED.
01063    */
01064 
01065   /* Let the SP know that we've created this group */
01066   if( This->dp2->spData.lpCB->CreateGroup )
01067   {
01068     DPSP_CREATEGROUPDATA data;
01069     DWORD dwCreateFlags = 0;
01070 
01071     TRACE( "Calling SP CreateGroup\n" );
01072 
01073     if( *lpidGroup == DPID_NOPARENT_GROUP )
01074       dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
01075 
01076     if( lpMsgHdr == NULL )
01077       dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
01078 
01079     if( dwFlags & DPGROUP_HIDDEN )
01080       dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
01081 
01082     data.idGroup           = *lpidGroup;
01083     data.dwFlags           = dwCreateFlags;
01084     data.lpSPMessageHeader = lpMsgHdr;
01085     data.lpISP             = This->dp2->spData.lpISP;
01086 
01087     (*This->dp2->spData.lpCB->CreateGroup)( &data );
01088   }
01089 
01090   /* Inform all other peers of the creation of a new group. If there are
01091    * no peers keep this event quiet.
01092    * Also if this message was sent to us, don't rebroadcast.
01093    */
01094   if( ( lpMsgHdr == NULL ) &&
01095       This->dp2->lpSessionDesc &&
01096       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
01097   {
01098     DPMSG_CREATEPLAYERORGROUP msg;
01099     msg.dwType = DPSYS_CREATEPLAYERORGROUP;
01100 
01101     msg.dwPlayerType     = DPPLAYERTYPE_GROUP;
01102     msg.dpId             = *lpidGroup;
01103     msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
01104     msg.lpData           = lpData;
01105     msg.dwDataSize       = dwDataSize;
01106     msg.dpnName          = *lpGroupName;
01107     msg.dpIdParent       = DPID_NOPARENT_GROUP;
01108     msg.dwFlags          = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
01109 
01110     /* FIXME: Correct to just use send effectively? */
01111     /* FIXME: Should size include data w/ message or just message "header" */
01112     /* FIXME: Check return code */
01113     DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
01114                0, 0, NULL, NULL, bAnsi );
01115   }
01116 
01117   return DP_OK;
01118 }
01119 
01120 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
01121           ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
01122             LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
01123 {
01124   *lpidGroup = DPID_UNKNOWN;
01125 
01126   return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
01127                             lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
01128 }
01129 
01130 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
01131           ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
01132             LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
01133 {
01134   *lpidGroup = DPID_UNKNOWN;
01135 
01136   return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
01137                             lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
01138 }
01139 
01140 
01141 static void
01142 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
01143                  LPVOID lpData, DWORD dwDataSize )
01144 {
01145   /* Clear out the data with this player */
01146   if( dwFlags & DPSET_LOCAL )
01147   {
01148     if ( lpGData->dwLocalDataSize != 0 )
01149     {
01150       HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
01151       lpGData->lpLocalData = NULL;
01152       lpGData->dwLocalDataSize = 0;
01153     }
01154   }
01155   else
01156   {
01157     if( lpGData->dwRemoteDataSize != 0 )
01158     {
01159       HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
01160       lpGData->lpRemoteData = NULL;
01161       lpGData->dwRemoteDataSize = 0;
01162     }
01163   }
01164 
01165   /* Reallocate for new data */
01166   if( lpData != NULL )
01167   {
01168     LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
01169                                   sizeof( dwDataSize ) );
01170     CopyMemory( lpNewData, lpData, dwDataSize );
01171 
01172     if( dwFlags & DPSET_LOCAL )
01173     {
01174       lpGData->lpLocalData     = lpData;
01175       lpGData->dwLocalDataSize = dwDataSize;
01176     }
01177     else
01178     {
01179       lpGData->lpRemoteData     = lpNewData;
01180       lpGData->dwRemoteDataSize = dwDataSize;
01181     }
01182   }
01183 
01184 }
01185 
01186 /* This function will just create the storage for the new player.  */
01187 static
01188 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
01189                               LPDPNAME lpName, DWORD dwFlags,
01190                               HANDLE hEvent, BOOL bAnsi )
01191 {
01192   lpPlayerData lpPData;
01193 
01194   TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
01195 
01196   /* Allocate the storage for the player and associate it with list element */
01197   lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
01198   if( lpPData == NULL )
01199   {
01200     return NULL;
01201   }
01202 
01203   /* Set the desired player ID */
01204   lpPData->dpid = *lpid;
01205 
01206   DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
01207 
01208   lpPData->dwFlags = dwFlags;
01209 
01210   /* If we were given an event handle, duplicate it */
01211   if( hEvent != 0 )
01212   {
01213     if( !DuplicateHandle( GetCurrentProcess(), hEvent,
01214                           GetCurrentProcess(), &lpPData->hEvent,
01215                           0, FALSE, DUPLICATE_SAME_ACCESS )
01216       )
01217     {
01218       /* FIXME: Memory leak */
01219       ERR( "Can't duplicate player msg handle %p\n", hEvent );
01220     }
01221   }
01222 
01223   /* Initialize the SP data section */
01224   lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
01225 
01226   TRACE( "Created player id 0x%08lx\n", *lpid );
01227 
01228   return lpPData;
01229 }
01230 
01231 /* Delete the contents of the DPNAME struct */
01232 static void
01233 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
01234 {
01235   HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->lpszShortNameA );
01236   HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->lpszLongNameA );
01237 }
01238 
01239 /* This method assumes that all links to it are already deleted */
01240 static void
01241 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
01242 {
01243   lpPlayerList lpPList;
01244 
01245   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
01246 
01247   DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
01248 
01249   if( lpPList == NULL )
01250   {
01251     ERR( "DPID 0x%08lx not found\n", dpid );
01252     return;
01253   }
01254 
01255   /* Verify that this is the last reference to the data */
01256   if( --(lpPList->lpPData->uRef) )
01257   {
01258     FIXME( "Why is this not the last reference to player?\n" );
01259     DebugBreak();
01260   }
01261 
01262   /* Delete player */
01263   DP_DeleteDPNameStruct( &lpPList->lpPData->name );
01264 
01265   CloseHandle( lpPList->lpPData->hEvent );
01266   HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
01267 
01268   /* Delete Player List object */
01269   HeapFree( GetProcessHeap(), 0, lpPList );
01270 }
01271 
01272 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
01273 {
01274   lpPlayerList lpPlayers;
01275 
01276   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
01277 
01278   DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
01279 
01280   return lpPlayers;
01281 }
01282 
01283 /* Basic area for Dst must already be allocated */
01284 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi )
01285 {
01286   if( lpSrc == NULL )
01287   {
01288     ZeroMemory( lpDst, sizeof( *lpDst ) );
01289     lpDst->dwSize = sizeof( *lpDst );
01290     return TRUE;
01291   }
01292 
01293   if( lpSrc->dwSize != sizeof( *lpSrc) )
01294   {
01295     return FALSE;
01296   }
01297 
01298   /* Delete any existing pointers */
01299   HeapFree( GetProcessHeap(), 0, lpDst->lpszShortNameA );
01300   HeapFree( GetProcessHeap(), 0, lpDst->lpszLongNameA );
01301 
01302   /* Copy as required */
01303   CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
01304 
01305   if( bAnsi )
01306   {
01307     if( lpSrc->lpszShortNameA )
01308     {
01309         lpDst->lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
01310                                              strlen(lpSrc->lpszShortNameA)+1 );
01311         strcpy( lpDst->lpszShortNameA, lpSrc->lpszShortNameA );
01312     }
01313     if( lpSrc->lpszLongNameA )
01314     {
01315         lpDst->lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
01316                                               strlen(lpSrc->lpszLongNameA)+1 );
01317         strcpy( lpDst->lpszLongNameA, lpSrc->lpszLongNameA );
01318     }
01319   }
01320   else
01321   {
01322     if( lpSrc->lpszShortNameA )
01323     {
01324         lpDst->lpszShortName = HeapAlloc( GetProcessHeap(), 0,
01325                                               (strlenW(lpSrc->lpszShortName)+1)*sizeof(WCHAR) );
01326         strcpyW( lpDst->lpszShortName, lpSrc->lpszShortName );
01327     }
01328     if( lpSrc->lpszLongNameA )
01329     {
01330         lpDst->lpszLongName = HeapAlloc( GetProcessHeap(), 0,
01331                                              (strlenW(lpSrc->lpszLongName)+1)*sizeof(WCHAR) );
01332         strcpyW( lpDst->lpszLongName, lpSrc->lpszLongName );
01333     }
01334   }
01335 
01336   return TRUE;
01337 }
01338 
01339 static void
01340 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
01341                   LPVOID lpData, DWORD dwDataSize )
01342 {
01343   /* Clear out the data with this player */
01344   if( dwFlags & DPSET_LOCAL )
01345   {
01346     if ( lpPData->dwLocalDataSize != 0 )
01347     {
01348       HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
01349       lpPData->lpLocalData = NULL;
01350       lpPData->dwLocalDataSize = 0;
01351     }
01352   }
01353   else
01354   {
01355     if( lpPData->dwRemoteDataSize != 0 )
01356     {
01357       HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
01358       lpPData->lpRemoteData = NULL;
01359       lpPData->dwRemoteDataSize = 0;
01360     }
01361   }
01362 
01363   /* Reallocate for new data */
01364   if( lpData != NULL )
01365   {
01366     LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
01367                                   sizeof( dwDataSize ) );
01368     CopyMemory( lpNewData, lpData, dwDataSize );
01369 
01370     if( dwFlags & DPSET_LOCAL )
01371     {
01372       lpPData->lpLocalData     = lpData;
01373       lpPData->dwLocalDataSize = dwDataSize;
01374     }
01375     else
01376     {
01377       lpPData->lpRemoteData     = lpNewData;
01378       lpPData->dwRemoteDataSize = dwDataSize;
01379     }
01380   }
01381 
01382 }
01383 
01384 static HRESULT WINAPI DP_IF_CreatePlayer
01385 ( IDirectPlay2Impl* This,
01386   LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
01387   LPDPID lpidPlayer,
01388   LPDPNAME lpPlayerName,
01389   HANDLE hEvent,
01390   LPVOID lpData,
01391   DWORD dwDataSize,
01392   DWORD dwFlags,
01393   BOOL bAnsi )
01394 {
01395   HRESULT hr = DP_OK;
01396   lpPlayerData lpPData;
01397   lpPlayerList lpPList;
01398   DWORD dwCreateFlags = 0;
01399 
01400   TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
01401          This, lpidPlayer, lpPlayerName, hEvent, lpData,
01402          dwDataSize, dwFlags, bAnsi );
01403 
01404   if( dwFlags == 0 )
01405   {
01406     dwFlags = DPPLAYER_SPECTATOR;
01407   }
01408 
01409   if( lpidPlayer == NULL )
01410   {
01411     return DPERR_INVALIDPARAMS;
01412   }
01413 
01414 
01415   /* Determine the creation flags for the player. These will be passed
01416    * to the name server if requesting a player id and to the SP when
01417    * informing it of the player creation
01418    */
01419   {
01420     if( dwFlags & DPPLAYER_SERVERPLAYER )
01421     {
01422       if( *lpidPlayer == DPID_SERVERPLAYER )
01423       {
01424         /* Server player for the host interface */
01425         dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
01426       }
01427       else if( *lpidPlayer == DPID_NAME_SERVER )
01428       {
01429         /* Name server - master of everything */
01430         dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
01431       }
01432       else
01433       {
01434         /* Server player for a non host interface */
01435         dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
01436       }
01437     }
01438 
01439     if( lpMsgHdr == NULL )
01440       dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
01441   }
01442 
01443   /* Verify we know how to handle all the flags */
01444   if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
01445          ( dwFlags & DPPLAYER_SPECTATOR )
01446        )
01447     )
01448   {
01449     /* Assume non fatal failure */
01450     ERR( "unknown dwFlags = 0x%08lx\n", dwFlags );
01451   }
01452 
01453   /* If the name is not specified, we must provide one */
01454   if( *lpidPlayer == DPID_UNKNOWN )
01455   {
01456     /* If we are the session master, we dish out the group/player ids */
01457     if( This->dp2->bHostInterface )
01458     {
01459       *lpidPlayer = DP_NextObjectId();
01460     }
01461     else
01462     {
01463       hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
01464 
01465       if( FAILED(hr) )
01466       {
01467         ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
01468         return hr;
01469       }
01470     }
01471   }
01472   else
01473   {
01474     /* FIXME: Would be nice to perhaps verify that we don't already have
01475      *        this player.
01476      */
01477   }
01478 
01479   /* FIXME: Should we be storing these dwFlags or the creation ones? */
01480   lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags,
01481                              hEvent, bAnsi );
01482 
01483   if( lpPData == NULL )
01484   {
01485     return DPERR_CANTADDPLAYER;
01486   }
01487 
01488   /* Create the list object and link it in */
01489   lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
01490   if( lpPList == NULL )
01491   {
01492     FIXME( "Memory leak\n" );
01493     return DPERR_CANTADDPLAYER;
01494   }
01495 
01496   lpPData->uRef = 1;
01497   lpPList->lpPData = lpPData;
01498 
01499   /* Add the player to the system group */
01500   DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
01501 
01502   /* Update the information and send it to all players in the session */
01503   DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
01504 
01505   /* Let the SP know that we've created this player */
01506   if( This->dp2->spData.lpCB->CreatePlayer )
01507   {
01508     DPSP_CREATEPLAYERDATA data;
01509 
01510     data.idPlayer          = *lpidPlayer;
01511     data.dwFlags           = dwCreateFlags;
01512     data.lpSPMessageHeader = lpMsgHdr;
01513     data.lpISP             = This->dp2->spData.lpISP;
01514 
01515     TRACE( "Calling SP CreatePlayer 0x%08lx: dwFlags: 0x%08lx lpMsgHdr: %p\n",
01516            *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
01517 
01518     hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
01519   }
01520 
01521   if( FAILED(hr) )
01522   {
01523     ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
01524     return hr;
01525   }
01526 
01527   /* Now let the SP know that this player is a member of the system group */
01528   if( This->dp2->spData.lpCB->AddPlayerToGroup )
01529   {
01530     DPSP_ADDPLAYERTOGROUPDATA data;
01531 
01532     data.idPlayer = *lpidPlayer;
01533     data.idGroup  = DPID_SYSTEM_GROUP;
01534     data.lpISP    = This->dp2->spData.lpISP;
01535 
01536     TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
01537 
01538     hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
01539   }
01540 
01541   if( FAILED(hr) )
01542   {
01543     ERR( "Failed to add player to sys group with sp: %s\n",
01544          DPLAYX_HresultToString(hr) );
01545     return hr;
01546   }
01547 
01548 #if 1
01549   if( This->dp2->bHostInterface == FALSE )
01550   {
01551     /* Let the name server know about the creation of this player */
01552     /* FIXME: Is this only to be done for the creation of a server player or
01553      *        is this used for regular players? If only for server players, move
01554      *        this call to DP_SecureOpen(...);
01555      */
01556 #if 0
01557     TRACE( "Sending message to self to get my addr\n" );
01558     DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
01559 #endif
01560 
01561     hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
01562   }
01563 #else
01564   /* Inform all other peers of the creation of a new player. If there are
01565    * no peers keep this quiet.
01566    * Also, if this was a remote event, no need to rebroadcast it.
01567    */
01568   if( ( lpMsgHdr == NULL ) &&
01569       This->dp2->lpSessionDesc &&
01570       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
01571   {
01572     DPMSG_CREATEPLAYERORGROUP msg;
01573     msg.dwType = DPSYS_CREATEPLAYERORGROUP;
01574 
01575     msg.dwPlayerType     = DPPLAYERTYPE_PLAYER;
01576     msg.dpId             = *lpidPlayer;
01577     msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
01578     msg.lpData           = lpData;
01579     msg.dwDataSize       = dwDataSize;
01580     msg.dpnName          = *lpPlayerName;
01581     msg.dpIdParent       = DPID_NOPARENT_GROUP;
01582     msg.dwFlags          = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
01583 
01584     /* FIXME: Correct to just use send effectively? */
01585     /* FIXME: Should size include data w/ message or just message "header" */
01586     /* FIXME: Check return code */
01587     hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
01588                     sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
01589   }
01590 #endif
01591 
01592   return hr;
01593 }
01594 
01595 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
01596           ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
01597             HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
01598 {
01599   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
01600 
01601   if( dwFlags & DPPLAYER_SERVERPLAYER )
01602   {
01603     *lpidPlayer = DPID_SERVERPLAYER;
01604   }
01605   else
01606   {
01607     *lpidPlayer = DPID_UNKNOWN;
01608   }
01609 
01610   return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
01611                            lpData, dwDataSize, dwFlags, TRUE );
01612 }
01613 
01614 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
01615           ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
01616             HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
01617 {
01618   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
01619 
01620   if( dwFlags & DPPLAYER_SERVERPLAYER )
01621   {
01622     *lpidPlayer = DPID_SERVERPLAYER;
01623   }
01624   else
01625   {
01626     *lpidPlayer = DPID_UNKNOWN;
01627   }
01628 
01629   return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
01630                            lpData, dwDataSize, dwFlags, FALSE );
01631 }
01632 
01633 static DPID DP_GetRemoteNextObjectId(void)
01634 {
01635   FIXME( ":stub\n" );
01636 
01637   /* Hack solution */
01638   return DP_NextObjectId();
01639 }
01640 
01641 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
01642           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
01643             DPID idPlayer, BOOL bAnsi )
01644 {
01645   HRESULT hr = DP_OK;
01646 
01647   lpGroupData  lpGData;
01648   lpPlayerList lpPList;
01649 
01650   TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n",
01651          This, lpMsgHdr, idGroup, idPlayer, bAnsi );
01652 
01653   /* Find the group */
01654   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
01655   {
01656     return DPERR_INVALIDGROUP;
01657   }
01658 
01659   /* Find the player */
01660   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
01661   {
01662     return DPERR_INVALIDPLAYER;
01663   }
01664 
01665   /* Remove the player shortcut from the group */
01666   DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
01667 
01668   if( lpPList == NULL )
01669   {
01670     return DPERR_INVALIDPLAYER;
01671   }
01672 
01673   /* One less reference */
01674   lpPList->lpPData->uRef--;
01675 
01676   /* Delete the Player List element */
01677   HeapFree( GetProcessHeap(), 0, lpPList );
01678 
01679   /* Inform the SP if they care */
01680   if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
01681   {
01682     DPSP_REMOVEPLAYERFROMGROUPDATA data;
01683 
01684     TRACE( "Calling SP RemovePlayerFromGroup\n" );
01685 
01686     data.idPlayer = idPlayer;
01687     data.idGroup  = idGroup;
01688     data.lpISP    = This->dp2->spData.lpISP;
01689 
01690     hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
01691   }
01692 
01693   /* Need to send a DELETEPLAYERFROMGROUP message */
01694   FIXME( "Need to send a message\n" );
01695 
01696   return hr;
01697 }
01698 
01699 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
01700           ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
01701 {
01702   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
01703   return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
01704 }
01705 
01706 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
01707           ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
01708 {
01709   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
01710   return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
01711 }
01712 
01713 typedef struct _DPRGOPContext
01714 {
01715   IDirectPlay3Impl* This;
01716   BOOL              bAnsi;
01717   DPID              idGroup;
01718 } DPRGOPContext, *lpDPRGOPContext;
01719 
01720 static BOOL CALLBACK
01721 cbRemoveGroupOrPlayer(
01722     DPID            dpId,
01723     DWORD           dwPlayerType,
01724     LPCDPNAME       lpName,
01725     DWORD           dwFlags,
01726     LPVOID          lpContext )
01727 {
01728   lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
01729 
01730   TRACE( "Removing element:0x%08lx (type:0x%08lx) from element:0x%08lx\n",
01731            dpId, dwPlayerType, lpCtxt->idGroup );
01732 
01733   if( dwPlayerType == DPPLAYERTYPE_GROUP )
01734   {
01735     if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
01736                                             dpId )
01737               )
01738       )
01739     {
01740       ERR( "Unable to delete group 0x%08lx from group 0x%08lx\n",
01741              dpId, lpCtxt->idGroup );
01742     }
01743   }
01744   else
01745   {
01746     if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
01747                                              NULL, lpCtxt->idGroup,
01748                                              dpId, lpCtxt->bAnsi )
01749               )
01750       )
01751     {
01752       ERR( "Unable to delete player 0x%08lx from grp 0x%08lx\n",
01753              dpId, lpCtxt->idGroup );
01754     }
01755   }
01756 
01757   return TRUE; /* Continue enumeration */
01758 }
01759 
01760 static HRESULT WINAPI DP_IF_DestroyGroup
01761           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
01762 {
01763   lpGroupData lpGData;
01764   DPRGOPContext context;
01765 
01766   FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n",
01767          This, lpMsgHdr, idGroup, bAnsi );
01768 
01769   /* Find the group */
01770   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
01771   {
01772     return DPERR_INVALIDPLAYER; /* yes player */
01773   }
01774 
01775   context.This    = (IDirectPlay3Impl*)This;
01776   context.bAnsi   = bAnsi;
01777   context.idGroup = idGroup;
01778 
01779   /* Remove all players that this group has */
01780   DP_IF_EnumGroupPlayers( This, idGroup, NULL,
01781                           cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
01782 
01783   /* Remove all links to groups that this group has since this is dp3 */
01784   DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
01785                            cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
01786 
01787   /* Remove this group from the parent group - if it has one */
01788   if( ( idGroup != DPID_SYSTEM_GROUP ) &&
01789       ( lpGData->parent != DPID_SYSTEM_GROUP )
01790     )
01791   {
01792     DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
01793                                 idGroup );
01794   }
01795 
01796   /* Now delete this group data and list from the system group */
01797   DP_DeleteGroup( This, idGroup );
01798 
01799   /* Let the SP know that we've destroyed this group */
01800   if( This->dp2->spData.lpCB->DeleteGroup )
01801   {
01802     DPSP_DELETEGROUPDATA data;
01803 
01804     FIXME( "data.dwFlags is incorrect\n" );
01805 
01806     data.idGroup = idGroup;
01807     data.dwFlags = 0;
01808     data.lpISP   = This->dp2->spData.lpISP;
01809 
01810     (*This->dp2->spData.lpCB->DeleteGroup)( &data );
01811   }
01812 
01813   FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
01814 
01815   return DP_OK;
01816 }
01817 
01818 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
01819           ( LPDIRECTPLAY2A iface, DPID idGroup )
01820 {
01821   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
01822   return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
01823 }
01824 
01825 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
01826           ( LPDIRECTPLAY2 iface, DPID idGroup )
01827 {
01828   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
01829   return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
01830 }
01831 
01832 typedef struct _DPFAGContext
01833 {
01834   IDirectPlay2Impl* This;
01835   DPID              idPlayer;
01836   BOOL              bAnsi;
01837 } DPFAGContext, *lpDPFAGContext;
01838 
01839 static HRESULT WINAPI DP_IF_DestroyPlayer
01840           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
01841 {
01842   DPFAGContext cbContext;
01843 
01844   FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n",
01845          This, lpMsgHdr, idPlayer, bAnsi );
01846 
01847   if( This->dp2->connectionInitialized == NO_PROVIDER )
01848   {
01849     return DPERR_UNINITIALIZED;
01850   }
01851 
01852   if( DP_FindPlayer( This, idPlayer ) == NULL )
01853   {
01854     return DPERR_INVALIDPLAYER;
01855   }
01856 
01857   /* FIXME: If the player is remote, we must be the host to delete this */
01858 
01859   cbContext.This     = This;
01860   cbContext.idPlayer = idPlayer;
01861   cbContext.bAnsi    = bAnsi;
01862 
01863   /* Find each group and call DeletePlayerFromGroup if the player is a
01864      member of the group */
01865   DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
01866                     (LPVOID)&cbContext, DPENUMGROUPS_ALL, bAnsi );
01867 
01868   /* Now delete player and player list from the sys group */
01869   DP_DeletePlayer( This, idPlayer );
01870 
01871   /* Let the SP know that we've destroyed this group */
01872   if( This->dp2->spData.lpCB->DeletePlayer )
01873   {
01874     DPSP_DELETEPLAYERDATA data;
01875 
01876     FIXME( "data.dwFlags is incorrect\n" );
01877 
01878     data.idPlayer = idPlayer;
01879     data.dwFlags = 0;
01880     data.lpISP   = This->dp2->spData.lpISP;
01881 
01882     (*This->dp2->spData.lpCB->DeletePlayer)( &data );
01883   }
01884 
01885   FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
01886 
01887   return DP_OK;
01888 }
01889 
01890 static BOOL CALLBACK
01891 cbDeletePlayerFromAllGroups(
01892     DPID            dpId,
01893     DWORD           dwPlayerType,
01894     LPCDPNAME       lpName,
01895     DWORD           dwFlags,
01896     LPVOID          lpContext )
01897 {
01898   lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
01899 
01900   if( dwPlayerType == DPPLAYERTYPE_GROUP )
01901   {
01902     DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
01903                                  lpCtxt->bAnsi );
01904 
01905     /* Enumerate all groups in this group since this will normally only
01906      * be called for top level groups
01907      */
01908     DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
01909                              dpId, NULL,
01910                              cbDeletePlayerFromAllGroups,
01911                              (LPVOID)lpContext, DPENUMGROUPS_ALL,
01912                              lpCtxt->bAnsi );
01913 
01914   }
01915   else
01916   {
01917     ERR( "Group callback has dwPlayerType = 0x%08lx\n", dwPlayerType );
01918   }
01919 
01920   return TRUE;
01921 }
01922 
01923 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
01924           ( LPDIRECTPLAY2A iface, DPID idPlayer )
01925 {
01926   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
01927   return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
01928 }
01929 
01930 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
01931           ( LPDIRECTPLAY2 iface, DPID idPlayer )
01932 {
01933   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
01934   return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
01935 }
01936 
01937 static HRESULT WINAPI DP_IF_EnumGroupPlayers
01938           ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
01939             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
01940             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
01941 {
01942   lpGroupData  lpGData;
01943   lpPlayerList lpPList;
01944 
01945   FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n",
01946           This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
01947           lpContext, dwFlags, bAnsi );
01948 
01949   if( This->dp2->connectionInitialized == NO_PROVIDER )
01950   {
01951     return DPERR_UNINITIALIZED;
01952   }
01953 
01954   /* Find the group */
01955   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
01956   {
01957     return DPERR_INVALIDGROUP;
01958   }
01959 
01960   if( DPQ_IS_EMPTY( lpGData->players ) )
01961   {
01962     return DP_OK;
01963   }
01964 
01965   lpPList = DPQ_FIRST( lpGData->players );
01966 
01967   /* Walk the players in this group */
01968   for( ;; )
01969   {
01970     /* We do not enum the name server or app server as they are of no
01971      * concequence to the end user.
01972      */
01973     if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
01974         ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
01975       )
01976     {
01977 
01978       /* FIXME: Need to add stuff for dwFlags checking */
01979 
01980       if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
01981                                    &lpPList->lpPData->name,
01982                                    lpPList->lpPData->dwFlags,
01983                                    lpContext )
01984         )
01985       {
01986         /* User requested break */
01987         return DP_OK;
01988       }
01989     }
01990 
01991     if( DPQ_IS_ENDOFLIST( lpPList->players ) )
01992     {
01993       break;
01994     }
01995 
01996     lpPList = DPQ_NEXT( lpPList->players );
01997   }
01998 
01999   return DP_OK;
02000 }
02001 
02002 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
02003           ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
02004             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
02005             LPVOID lpContext, DWORD dwFlags )
02006 {
02007   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02008   return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
02009                                lpEnumPlayersCallback2, lpContext,
02010                                dwFlags, TRUE );
02011 }
02012 
02013 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
02014           ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
02015             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
02016             LPVOID lpContext, DWORD dwFlags )
02017 {
02018   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02019   return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
02020                                lpEnumPlayersCallback2, lpContext,
02021                                dwFlags, FALSE );
02022 }
02023 
02024 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
02025 static HRESULT WINAPI DP_IF_EnumGroups
02026           ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
02027             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
02028             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
02029 {
02030   return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
02031                                   DPID_SYSTEM_GROUP, lpguidInstance,
02032                                   lpEnumPlayersCallback2, lpContext,
02033                                   dwFlags, bAnsi );
02034 }
02035 
02036 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
02037           ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
02038             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
02039             LPVOID lpContext, DWORD dwFlags )
02040 {
02041   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02042   return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
02043                          lpContext, dwFlags, TRUE );
02044 }
02045 
02046 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
02047           ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
02048             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
02049             LPVOID lpContext, DWORD dwFlags )
02050 {
02051   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02052   return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
02053                          lpContext, dwFlags, FALSE );
02054 }
02055 
02056 static HRESULT WINAPI DP_IF_EnumPlayers
02057           ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
02058             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
02059             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
02060 {
02061   return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
02062                                  lpEnumPlayersCallback2, lpContext,
02063                                  dwFlags, bAnsi );
02064 }
02065 
02066 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
02067           ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
02068             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
02069             LPVOID lpContext, DWORD dwFlags )
02070 {
02071   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02072   return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
02073                           lpContext, dwFlags, TRUE );
02074 }
02075 
02076 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
02077           ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
02078             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
02079             LPVOID lpContext, DWORD dwFlags )
02080 {
02081   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02082   return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
02083                           lpContext, dwFlags, FALSE );
02084 }
02085 
02086 /* This function should call the registered callback function that the user
02087    passed into EnumSessions for each entry available.
02088  */
02089 static void DP_InvokeEnumSessionCallbacks
02090        ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
02091          LPVOID lpNSInfo,
02092          DWORD dwTimeout,
02093          LPVOID lpContext )
02094 {
02095   LPDPSESSIONDESC2 lpSessionDesc;
02096 
02097   FIXME( ": not checking for conditions\n" );
02098 
02099   /* Not sure if this should be pruning but it's convenient */
02100   NS_PruneSessionCache( lpNSInfo );
02101 
02102   NS_ResetSessionEnumeration( lpNSInfo );
02103 
02104   /* Enumerate all sessions */
02105   /* FIXME: Need to indicate ANSI */
02106   while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
02107   {
02108     TRACE( "EnumSessionsCallback2 invoked\n" );
02109     if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
02110     {
02111       return;
02112     }
02113   }
02114 
02115   /* Invoke one last time to indicate that there is no more to come */
02116   lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
02117 }
02118 
02119 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
02120 {
02121   EnumSessionAsyncCallbackData* data = (EnumSessionAsyncCallbackData*)lpContext;
02122   HANDLE hSuicideRequest = data->hSuicideRequest;
02123   DWORD dwTimeout = data->dwTimeout;
02124 
02125   TRACE( "Thread started with timeout = 0x%08lx\n", dwTimeout );
02126 
02127   for( ;; )
02128   {
02129     HRESULT hr;
02130 
02131     /* Sleep up to dwTimeout waiting for request to terminate thread */
02132     if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
02133     {
02134       TRACE( "Thread terminating on terminate request\n" );
02135       break;
02136     }
02137 
02138     /* Now resend the enum request */
02139     hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
02140                                          data->dwEnumSessionFlags,
02141                                          data->lpSpData );
02142 
02143     if( FAILED(hr) )
02144     {
02145       ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
02146       /* FIXME: Should we kill this thread? How to inform the main thread? */
02147     }
02148 
02149   }
02150 
02151   TRACE( "Thread terminating\n" );
02152 
02153   /* Clean up the thread data */
02154   CloseHandle( hSuicideRequest );
02155   HeapFree( GetProcessHeap(), 0, lpContext );
02156 
02157   /* FIXME: Need to have some notification to main app thread that this is
02158    *        dead. It would serve two purposes. 1) allow sync on termination
02159    *        so that we don't actually send something to ourselves when we
02160    *        become name server (race condition) and 2) so that if we die
02161    *        abnormally something else will be able to tell.
02162    */
02163 
02164   return 1;
02165 }
02166 
02167 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
02168 {
02169   /* Does a thread exist? If so we were doing an async enum session */
02170   if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
02171   {
02172     TRACE( "Killing EnumSession thread %p\n",
02173            This->dp2->hEnumSessionThread );
02174 
02175     /* Request that the thread kill itself nicely */
02176     SetEvent( This->dp2->hKillEnumSessionThreadEvent );
02177     CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
02178 
02179     /* We no longer need to know about the thread */
02180     CloseHandle( This->dp2->hEnumSessionThread );
02181 
02182     This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
02183   }
02184 }
02185 
02186 static HRESULT WINAPI DP_IF_EnumSessions
02187           ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
02188             LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
02189             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
02190 {
02191   HRESULT hr = DP_OK;
02192 
02193   TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx,%u)\n",
02194          This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
02195          bAnsi );
02196 
02197   /* Can't enumerate if the interface is already open */
02198   if( This->dp2->bConnectionOpen )
02199   {
02200     return DPERR_GENERIC;
02201   }
02202 
02203 #if 1
02204   /* The loading of a lobby provider _seems_ to require a backdoor loading
02205    * of the service provider to also associate with this DP object. This is
02206    * because the app doesn't seem to have to call EnumConnections and
02207    * InitializeConnection for the SP before calling this method. As such
02208    * we'll do their dirty work for them with a quick hack so as to always
02209    * load the TCP/IP service provider.
02210    *
02211    * The correct solution would seem to involve creating a dialog box which
02212    * contains the possible SPs. These dialog boxes most likely follow SDK
02213    * examples.
02214    */
02215    if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
02216    {
02217      LPVOID lpConnection;
02218      DWORD  dwSize;
02219 
02220      WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
02221 
02222      if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
02223      {
02224        ERR( "Can't build compound addr\n" );
02225        return DPERR_GENERIC;
02226      }
02227 
02228      hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
02229                                       0, bAnsi );
02230      if( FAILED(hr) )
02231      {
02232        return hr;
02233      }
02234 
02235      /* Free up the address buffer */
02236      HeapFree( GetProcessHeap(), 0, lpConnection );
02237 
02238      /* The SP is now initialized */
02239      This->dp2->bSPInitialized = TRUE;
02240    }
02241 #endif
02242 
02243 
02244   /* Use the service provider default? */
02245   if( dwTimeout == 0 )
02246   {
02247     DPCAPS spCaps;
02248     spCaps.dwSize = sizeof( spCaps );
02249 
02250     DP_IF_GetCaps( This, &spCaps, 0 );
02251     dwTimeout = spCaps.dwTimeout;
02252 
02253     /* The service provider doesn't provide one either! */
02254     if( dwTimeout == 0 )
02255     {
02256       /* Provide the TCP/IP default */
02257       dwTimeout = DPMSG_WAIT_5_SECS;
02258     }
02259   }
02260 
02261   if( dwFlags & DPENUMSESSIONS_STOPASYNC )
02262   {
02263     DP_KillEnumSessionThread( This );
02264     return hr;
02265   }
02266 
02267   /* FIXME: Interface locking sucks in this method */
02268   if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
02269   {
02270     /* Enumerate everything presently in the local session cache */
02271     DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
02272                                    This->dp2->lpNameServerData, dwTimeout,
02273                                    lpContext );
02274 
02275 
02276     /* See if we've already created a thread to service this interface */
02277     if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
02278     {
02279       DWORD dwThreadId;
02280 
02281       /* Send the first enum request inline since the user may cancel a dialog
02282        * if one is presented. Also, may also have a connecting return code.
02283        */
02284       hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
02285                                            dwFlags, &This->dp2->spData );
02286 
02287       if( !FAILED(hr) )
02288       {
02289         EnumSessionAsyncCallbackData* lpData
02290           = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
02291         /* FIXME: need to kill the thread on object deletion */
02292         lpData->lpSpData  = &This->dp2->spData;
02293 
02294         CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
02295         lpData->dwEnumSessionFlags = dwFlags;
02296         lpData->dwTimeout = dwTimeout;
02297 
02298         This->dp2->hKillEnumSessionThreadEvent =
02299           CreateEventW( NULL, TRUE, FALSE, NULL );
02300 
02301         if( !DuplicateHandle( GetCurrentProcess(),
02302                               This->dp2->hKillEnumSessionThreadEvent,
02303                               GetCurrentProcess(),
02304                               &lpData->hSuicideRequest,
02305                               0, FALSE, DUPLICATE_SAME_ACCESS )
02306           )
02307         {
02308           ERR( "Can't duplicate thread killing handle\n" );
02309         }
02310 
02311         TRACE( ": creating EnumSessionsRequest thread\n" );
02312 
02313         This->dp2->hEnumSessionThread = CreateThread( NULL,
02314                                                       0,
02315                                                       DP_EnumSessionsSendAsyncRequestThread,
02316                                                       lpData,
02317                                                       0,
02318                                                       &dwThreadId );
02319       }
02320     }
02321   }
02322   else
02323   {
02324     /* Invalidate the session cache for the interface */
02325     NS_InvalidateSessionCache( This->dp2->lpNameServerData );
02326 
02327     /* Send the broadcast for session enumeration */
02328     hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
02329                                          dwFlags,
02330                                          &This->dp2->spData );
02331 
02332 
02333     SleepEx( dwTimeout, FALSE );
02334 
02335     DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
02336                                    This->dp2->lpNameServerData, dwTimeout,
02337                                    lpContext );
02338   }
02339 
02340   return hr;
02341 }
02342 
02343 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
02344           ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
02345             LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
02346             LPVOID lpContext, DWORD dwFlags )
02347 {
02348   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02349   return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
02350                              lpContext, dwFlags, TRUE );
02351 }
02352 
02353 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
02354           ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
02355             LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
02356             LPVOID lpContext, DWORD dwFlags )
02357 {
02358   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02359   return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
02360                              lpContext, dwFlags, FALSE );
02361 }
02362 
02363 static HRESULT WINAPI DP_IF_GetPlayerCaps
02364           ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
02365             DWORD dwFlags )
02366 {
02367   DPSP_GETCAPSDATA data;
02368 
02369   TRACE("(%p)->(0x%08lx,%p,0x%08lx)\n", This, idPlayer, lpDPCaps, dwFlags);
02370 
02371   /* Query the service provider */
02372   data.idPlayer = idPlayer;
02373   data.dwFlags  = dwFlags;
02374   data.lpCaps   = lpDPCaps;
02375   data.lpISP    = This->dp2->spData.lpISP;
02376 
02377   return (*This->dp2->spData.lpCB->GetCaps)( &data );
02378 }
02379 
02380 static HRESULT WINAPI DP_IF_GetCaps
02381           ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
02382 {
02383   return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
02384 }
02385 
02386 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
02387           ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
02388 {
02389   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02390   return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
02391 }
02392 
02393 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
02394           ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
02395 {
02396   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02397   return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
02398 }
02399 
02400 static HRESULT WINAPI DP_IF_GetGroupData
02401           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
02402             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
02403 {
02404   lpGroupData lpGData;
02405   DWORD dwRequiredBufferSize;
02406   LPVOID lpCopyDataFrom;
02407 
02408   TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n",
02409          This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
02410 
02411   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
02412   {
02413     return DPERR_INVALIDGROUP;
02414   }
02415 
02416   /* How much buffer is required? */
02417   if( dwFlags & DPSET_LOCAL )
02418   {
02419     dwRequiredBufferSize = lpGData->dwLocalDataSize;
02420     lpCopyDataFrom       = lpGData->lpLocalData;
02421   }
02422   else
02423   {
02424     dwRequiredBufferSize = lpGData->dwRemoteDataSize;
02425     lpCopyDataFrom       = lpGData->lpRemoteData;
02426   }
02427 
02428   /* Is the user requesting to know how big a buffer is required? */
02429   if( ( lpData == NULL ) ||
02430       ( *lpdwDataSize < dwRequiredBufferSize )
02431     )
02432   {
02433     *lpdwDataSize = dwRequiredBufferSize;
02434     return DPERR_BUFFERTOOSMALL;
02435   }
02436 
02437   CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
02438 
02439   return DP_OK;
02440 }
02441 
02442 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
02443           ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
02444             LPDWORD lpdwDataSize, DWORD dwFlags )
02445 {
02446   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02447   return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
02448                            dwFlags, TRUE );
02449 }
02450 
02451 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
02452           ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
02453             LPDWORD lpdwDataSize, DWORD dwFlags )
02454 {
02455   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02456   return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
02457                            dwFlags, FALSE );
02458 }
02459 
02460 static HRESULT WINAPI DP_IF_GetGroupName
02461           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
02462             LPDWORD lpdwDataSize, BOOL bAnsi )
02463 {
02464   lpGroupData lpGData;
02465   LPDPNAME    lpName = (LPDPNAME)lpData;
02466   DWORD       dwRequiredDataSize;
02467 
02468   FIXME("(%p)->(0x%08lx,%p,%p,%u) ANSI ignored\n",
02469           This, idGroup, lpData, lpdwDataSize, bAnsi );
02470 
02471   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
02472   {
02473     return DPERR_INVALIDGROUP;
02474   }
02475 
02476   dwRequiredDataSize = lpGData->name.dwSize;
02477 
02478   if( lpGData->name.lpszShortNameA )
02479   {
02480     dwRequiredDataSize += strlen( lpGData->name.lpszShortNameA ) + 1;
02481   }
02482 
02483   if( lpGData->name.lpszLongNameA )
02484   {
02485     dwRequiredDataSize += strlen( lpGData->name.lpszLongNameA ) + 1;
02486   }
02487 
02488   if( ( lpData == NULL ) ||
02489       ( *lpdwDataSize < dwRequiredDataSize )
02490     )
02491   {
02492     *lpdwDataSize = dwRequiredDataSize;
02493     return DPERR_BUFFERTOOSMALL;
02494   }
02495 
02496   /* Copy the structure */
02497   CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
02498 
02499   if( lpGData->name.lpszShortNameA )
02500   {
02501     strcpy( ((char*)lpName)+lpGData->name.dwSize,
02502             lpGData->name.lpszShortNameA );
02503   }
02504   else
02505   {
02506     lpName->lpszShortNameA = NULL;
02507   }
02508 
02509   if( lpGData->name.lpszShortNameA )
02510   {
02511     strcpy( ((char*)lpName)+lpGData->name.dwSize,
02512             lpGData->name.lpszLongNameA );
02513   }
02514   else
02515   {
02516     lpName->lpszLongNameA = NULL;
02517   }
02518 
02519   return DP_OK;
02520 }
02521 
02522 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
02523           ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
02524             LPDWORD lpdwDataSize )
02525 {
02526   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02527   return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
02528 }
02529 
02530 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
02531           ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
02532             LPDWORD lpdwDataSize )
02533 {
02534   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02535   return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
02536 }
02537 
02538 static HRESULT WINAPI DP_IF_GetMessageCount
02539           ( IDirectPlay2Impl* This, DPID idPlayer,
02540             LPDWORD lpdwCount, BOOL bAnsi )
02541 {
02542   FIXME("(%p)->(0x%08lx,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
02543   return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
02544                                 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
02545                                 bAnsi );
02546 }
02547 
02548 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
02549           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
02550 {
02551   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02552   return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
02553 }
02554 
02555 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
02556           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
02557 {
02558   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02559   return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
02560 }
02561 
02562 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
02563           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
02564 {
02565   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02566   FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
02567   return DP_OK;
02568 }
02569 
02570 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
02571           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
02572 {
02573   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02574   FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
02575   return DP_OK;
02576 }
02577 
02578 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
02579           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
02580             DWORD dwFlags )
02581 {
02582   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02583   return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
02584 }
02585 
02586 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
02587           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
02588             DWORD dwFlags )
02589 {
02590   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02591   return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
02592 }
02593 
02594 static HRESULT WINAPI DP_IF_GetPlayerData
02595           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
02596             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
02597 {
02598   lpPlayerList lpPList;
02599   DWORD dwRequiredBufferSize;
02600   LPVOID lpCopyDataFrom;
02601 
02602   TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n",
02603          This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
02604 
02605   if( This->dp2->connectionInitialized == NO_PROVIDER )
02606   {
02607     return DPERR_UNINITIALIZED;
02608   }
02609 
02610   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
02611   {
02612     return DPERR_INVALIDPLAYER;
02613   }
02614 
02615   /* How much buffer is required? */
02616   if( dwFlags & DPSET_LOCAL )
02617   {
02618     dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
02619     lpCopyDataFrom       = lpPList->lpPData->lpLocalData;
02620   }
02621   else
02622   {
02623     dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
02624     lpCopyDataFrom       = lpPList->lpPData->lpRemoteData;
02625   }
02626 
02627   /* Is the user requesting to know how big a buffer is required? */
02628   if( ( lpData == NULL ) ||
02629       ( *lpdwDataSize < dwRequiredBufferSize )
02630     )
02631   {
02632     *lpdwDataSize = dwRequiredBufferSize;
02633     return DPERR_BUFFERTOOSMALL;
02634   }
02635 
02636   CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
02637 
02638   return DP_OK;
02639 }
02640 
02641 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
02642           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
02643             LPDWORD lpdwDataSize, DWORD dwFlags )
02644 {
02645   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02646   return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
02647                             dwFlags, TRUE );
02648 }
02649 
02650 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
02651           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
02652             LPDWORD lpdwDataSize, DWORD dwFlags )
02653 {
02654   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02655   return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
02656                             dwFlags, FALSE );
02657 }
02658 
02659 static HRESULT WINAPI DP_IF_GetPlayerName
02660           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
02661             LPDWORD lpdwDataSize, BOOL bAnsi )
02662 {
02663   lpPlayerList lpPList;
02664   LPDPNAME    lpName = (LPDPNAME)lpData;
02665   DWORD       dwRequiredDataSize;
02666 
02667   FIXME( "(%p)->(0x%08lx,%p,%p,%u): ANSI\n",
02668          This, idPlayer, lpData, lpdwDataSize, bAnsi );
02669 
02670   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
02671   {
02672     return DPERR_INVALIDPLAYER;
02673   }
02674 
02675   dwRequiredDataSize = lpPList->lpPData->name.dwSize;
02676 
02677   if( lpPList->lpPData->name.lpszShortNameA )
02678   {
02679     dwRequiredDataSize += strlen( lpPList->lpPData->name.lpszShortNameA ) + 1;
02680   }
02681 
02682   if( lpPList->lpPData->name.lpszLongNameA )
02683   {
02684     dwRequiredDataSize += strlen( lpPList->lpPData->name.lpszLongNameA ) + 1;
02685   }
02686 
02687   if( ( lpData == NULL ) ||
02688       ( *lpdwDataSize < dwRequiredDataSize )
02689     )
02690   {
02691     *lpdwDataSize = dwRequiredDataSize;
02692     return DPERR_BUFFERTOOSMALL;
02693   }
02694 
02695   /* Copy the structure */
02696   CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
02697 
02698   if( lpPList->lpPData->name.lpszShortNameA )
02699   {
02700     strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
02701             lpPList->lpPData->name.lpszShortNameA );
02702   }
02703   else
02704   {
02705     lpName->lpszShortNameA = NULL;
02706   }
02707 
02708   if( lpPList->lpPData->name.lpszShortNameA )
02709   {
02710     strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
02711             lpPList->lpPData->name.lpszLongNameA );
02712   }
02713   else
02714   {
02715     lpName->lpszLongNameA = NULL;
02716   }
02717 
02718   return DP_OK;
02719 }
02720 
02721 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
02722           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
02723             LPDWORD lpdwDataSize )
02724 {
02725   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02726   return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
02727 }
02728 
02729 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
02730           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
02731             LPDWORD lpdwDataSize )
02732 {
02733   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02734   return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
02735 }
02736 
02737 static HRESULT WINAPI DP_GetSessionDesc
02738           ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
02739             BOOL bAnsi )
02740 {
02741   DWORD dwRequiredSize;
02742 
02743   TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
02744 
02745   if( This->dp2->connectionInitialized == NO_PROVIDER )
02746   {
02747     return DPERR_UNINITIALIZED;
02748   }
02749 
02750   if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
02751   {
02752     return DPERR_INVALIDPARAMS;
02753   }
02754 
02755   /* FIXME: Get from This->dp2->lpSessionDesc */
02756   dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
02757 
02758   if ( ( lpData == NULL ) ||
02759        ( *lpdwDataSize < dwRequiredSize )
02760      )
02761   {
02762     *lpdwDataSize = dwRequiredSize;
02763     return DPERR_BUFFERTOOSMALL;
02764   }
02765 
02766   DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
02767 
02768   return DP_OK;
02769 }
02770 
02771 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
02772           ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
02773 {
02774   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02775   return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
02776 }
02777 
02778 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
02779           ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
02780 {
02781   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02782   return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
02783 }
02784 
02785 /* Intended only for COM compatibility. Always returns an error. */
02786 static HRESULT WINAPI DirectPlay2AImpl_Initialize
02787           ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
02788 {
02789   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02790   TRACE("(%p)->(%p): stub\n", This, lpGUID );
02791   return DPERR_ALREADYINITIALIZED;
02792 }
02793 
02794 /* Intended only for COM compatibility. Always returns an error. */
02795 static HRESULT WINAPI DirectPlay2WImpl_Initialize
02796           ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
02797 {
02798   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02799   TRACE("(%p)->(%p): stub\n", This, lpGUID );
02800   return DPERR_ALREADYINITIALIZED;
02801 }
02802 
02803 
02804 static HRESULT WINAPI DP_SecureOpen
02805           ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
02806             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
02807             BOOL bAnsi )
02808 {
02809   HRESULT hr = DP_OK;
02810 
02811   FIXME( "(%p)->(%p,0x%08lx,%p,%p): partial stub\n",
02812          This, lpsd, dwFlags, lpSecurity, lpCredentials );
02813 
02814   if( This->dp2->bConnectionOpen )
02815   {
02816     TRACE( ": rejecting already open connection.\n" );
02817     return DPERR_ALREADYINITIALIZED;
02818   }
02819 
02820   /* If we're enumerating, kill the thread */
02821   DP_KillEnumSessionThread( This );
02822 
02823   if( dwFlags & DPOPEN_CREATE )
02824   {
02825     /* Rightoo - this computer is the host and the local computer needs to be
02826        the name server so that others can join this session */
02827     NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
02828 
02829     This->dp2->bHostInterface = TRUE;
02830 
02831     hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
02832     if( FAILED( hr ) )
02833     {
02834       ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
02835       return hr;
02836     }
02837   }
02838 
02839   /* Invoke the conditional callback for the service provider */
02840   if( This->dp2->spData.lpCB->Open )
02841   {
02842     DPSP_OPENDATA data;
02843 
02844     FIXME( "Not all data fields are correct. Need new parameter\n" );
02845 
02846     data.bCreate           = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
02847     data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
02848                                                         : NS_GetNSAddr( This->dp2->lpNameServerData );
02849     data.lpISP             = This->dp2->spData.lpISP;
02850     data.bReturnStatus     = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
02851     data.dwOpenFlags       = dwFlags;
02852     data.dwSessionFlags    = This->dp2->lpSessionDesc->dwFlags;
02853 
02854     hr = (*This->dp2->spData.lpCB->Open)(&data);
02855     if( FAILED( hr ) )
02856     {
02857       ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
02858       return hr;
02859     }
02860   }
02861 
02862   {
02863     /* Create the system group of which everything is a part of */
02864     DPID systemGroup = DPID_SYSTEM_GROUP;
02865 
02866     hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
02867                             NULL, 0, 0, TRUE );
02868 
02869   }
02870 
02871   if( dwFlags & DPOPEN_JOIN )
02872   {
02873     DPID dpidServerId = DPID_UNKNOWN;
02874 
02875     /* Create the server player for this interface. This way we can receive
02876      * messages for this session.
02877      */
02878     /* FIXME: I suppose that we should be setting an event for a receive
02879      *        type of thing. That way the messaging thread could know to wake
02880      *        up. DPlay would then trigger the hEvent for the player the
02881      *        message is directed to.
02882      */
02883     hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
02884                              0,
02885                              DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
02886 
02887   }
02888   else if( dwFlags & DPOPEN_CREATE )
02889   {
02890     DPID dpidNameServerId = DPID_NAME_SERVER;
02891 
02892     hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
02893                              0, DPPLAYER_SERVERPLAYER, bAnsi );
02894   }
02895 
02896   if( FAILED(hr) )
02897   {
02898     ERR( "Couldn't create name server/system player: %s\n",
02899          DPLAYX_HresultToString(hr) );
02900   }
02901 
02902   return hr;
02903 }
02904 
02905 static HRESULT WINAPI DirectPlay2AImpl_Open
02906           ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
02907 {
02908   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02909   TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
02910   return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
02911 }
02912 
02913 static HRESULT WINAPI DirectPlay2WImpl_Open
02914           ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
02915 {
02916   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02917   TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
02918   return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
02919 }
02920 
02921 static HRESULT WINAPI DP_IF_Receive
02922           ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
02923             DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
02924 {
02925   LPDPMSG lpMsg = NULL;
02926 
02927   FIXME( "(%p)->(%p,%p,0x%08lx,%p,%p,%u): stub\n",
02928          This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
02929 
02930   if( This->dp2->connectionInitialized == NO_PROVIDER )
02931   {
02932     return DPERR_UNINITIALIZED;
02933   }
02934 
02935   if( dwFlags == 0 )
02936   {
02937     dwFlags = DPRECEIVE_ALL;
02938   }
02939 
02940   /* If the lpData is NULL, we must be peeking the message */
02941   if(  ( lpData == NULL ) &&
02942       !( dwFlags & DPRECEIVE_PEEK )
02943     )
02944   {
02945     return DPERR_INVALIDPARAMS;
02946   }
02947 
02948   if( dwFlags & DPRECEIVE_ALL )
02949   {
02950     lpMsg = This->dp2->receiveMsgs.lpQHFirst;
02951 
02952     if( !( dwFlags & DPRECEIVE_PEEK ) )
02953     {
02954       FIXME( "Remove from queue\n" );
02955     }
02956   }
02957   else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
02958            ( dwFlags & DPRECEIVE_FROMPLAYER )
02959          )
02960   {
02961     FIXME( "Find matching message 0x%08lx\n", dwFlags );
02962   }
02963   else
02964   {
02965     ERR( "Hmmm..dwFlags 0x%08lx\n", dwFlags );
02966   }
02967 
02968   if( lpMsg == NULL )
02969   {
02970     return DPERR_NOMESSAGES;
02971   }
02972 
02973   /* Copy into the provided buffer */
02974   CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
02975 
02976   return DP_OK;
02977 }
02978 
02979 static HRESULT WINAPI DirectPlay2AImpl_Receive
02980           ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
02981             DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
02982 {
02983   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02984   return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
02985                         lpData, lpdwDataSize, TRUE );
02986 }
02987 
02988 static HRESULT WINAPI DirectPlay2WImpl_Receive
02989           ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
02990             DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
02991 {
02992   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
02993   return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
02994                         lpData, lpdwDataSize, FALSE );
02995 }
02996 
02997 static HRESULT WINAPI DirectPlay2AImpl_Send
02998           ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
02999 {
03000   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03001   return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
03002                     0, 0, NULL, NULL, TRUE );
03003 }
03004 
03005 static HRESULT WINAPI DirectPlay2WImpl_Send
03006           ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
03007 {
03008   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03009   return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
03010                     0, 0, NULL, NULL, FALSE );
03011 }
03012 
03013 static HRESULT WINAPI DP_IF_SetGroupData
03014           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
03015             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
03016 {
03017   lpGroupData lpGData;
03018 
03019   TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n",
03020          This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
03021 
03022   /* Parameter check */
03023   if( ( lpData == NULL ) &&
03024       ( dwDataSize != 0 )
03025     )
03026   {
03027     return DPERR_INVALIDPARAMS;
03028   }
03029 
03030   /* Find the pointer to the data for this player */
03031   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
03032   {
03033     return DPERR_INVALIDOBJECT;
03034   }
03035 
03036   if( !(dwFlags & DPSET_LOCAL) )
03037   {
03038     FIXME( "Was this group created by this interface?\n" );
03039     /* FIXME: If this is a remote update need to allow it but not
03040      *        send a message.
03041      */
03042   }
03043 
03044   DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
03045 
03046   /* FIXME: Only send a message if this group is local to the session otherwise
03047    * it will have been rejected above
03048    */
03049   if( !(dwFlags & DPSET_LOCAL) )
03050   {
03051     FIXME( "Send msg?\n" );
03052   }
03053 
03054   return DP_OK;
03055 }
03056 
03057 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
03058           ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
03059             DWORD dwDataSize, DWORD dwFlags )
03060 {
03061   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03062   return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
03063 }
03064 
03065 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
03066           ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
03067             DWORD dwDataSize, DWORD dwFlags )
03068 {
03069   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03070   return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
03071 }
03072 
03073 static HRESULT WINAPI DP_IF_SetGroupName
03074           ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
03075             DWORD dwFlags, BOOL bAnsi )
03076 {
03077   lpGroupData lpGData;
03078 
03079   TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", This, idGroup,
03080          lpGroupName, dwFlags, bAnsi );
03081 
03082   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
03083   {
03084     return DPERR_INVALIDGROUP;
03085   }
03086 
03087   DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
03088 
03089   /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
03090   FIXME( "Message not sent and dwFlags ignored\n" );
03091 
03092   return DP_OK;
03093 }
03094 
03095 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
03096           ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
03097             DWORD dwFlags )
03098 {
03099   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03100   return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
03101 }
03102 
03103 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
03104           ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
03105             DWORD dwFlags )
03106 {
03107   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03108   return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
03109 }
03110 
03111 static HRESULT WINAPI DP_IF_SetPlayerData
03112           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
03113             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
03114 {
03115   lpPlayerList lpPList;
03116 
03117   TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n",
03118          This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
03119 
03120   /* Parameter check */
03121   if( ( lpData == NULL ) &&
03122       ( dwDataSize != 0 )
03123     )
03124   {
03125     return DPERR_INVALIDPARAMS;
03126   }
03127 
03128   /* Find the pointer to the data for this player */
03129   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
03130   {
03131     return DPERR_INVALIDPLAYER;
03132   }
03133 
03134   if( !(dwFlags & DPSET_LOCAL) )
03135   {
03136     FIXME( "Was this group created by this interface?\n" );
03137     /* FIXME: If this is a remote update need to allow it but not
03138      *        send a message.
03139      */
03140   }
03141 
03142   DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
03143 
03144   if( !(dwFlags & DPSET_LOCAL) )
03145   {
03146     FIXME( "Send msg?\n" );
03147   }
03148 
03149   return DP_OK;
03150 }
03151 
03152 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
03153           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
03154             DWORD dwDataSize, DWORD dwFlags )
03155 {
03156   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03157   return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
03158                               dwFlags, TRUE );
03159 }
03160 
03161 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
03162           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
03163             DWORD dwDataSize, DWORD dwFlags )
03164 {
03165   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03166   return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
03167                               dwFlags, FALSE );
03168 }
03169 
03170 static HRESULT WINAPI DP_IF_SetPlayerName
03171           ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
03172             DWORD dwFlags, BOOL bAnsi )
03173 {
03174   lpPlayerList lpPList;
03175 
03176   TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n",
03177          This, idPlayer, lpPlayerName, dwFlags, bAnsi );
03178 
03179   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
03180   {
03181     return DPERR_INVALIDGROUP;
03182   }
03183 
03184   DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
03185 
03186   /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
03187   FIXME( "Message not sent and dwFlags ignored\n" );
03188 
03189   return DP_OK;
03190 }
03191 
03192 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
03193           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
03194             DWORD dwFlags )
03195 {
03196   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03197   return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
03198 }
03199 
03200 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
03201           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
03202             DWORD dwFlags )
03203 {
03204   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03205   return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
03206 }
03207 
03208 static HRESULT WINAPI DP_SetSessionDesc
03209           ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
03210             DWORD dwFlags, BOOL bInitial, BOOL bAnsi  )
03211 {
03212   DWORD            dwRequiredSize;
03213   LPDPSESSIONDESC2 lpTempSessDesc;
03214 
03215   TRACE( "(%p)->(%p,0x%08lx,%u,%u)\n",
03216          This, lpSessDesc, dwFlags, bInitial, bAnsi );
03217 
03218   if( This->dp2->connectionInitialized == NO_PROVIDER )
03219   {
03220     return DPERR_UNINITIALIZED;
03221   }
03222 
03223   if( dwFlags )
03224   {
03225     return DPERR_INVALIDPARAMS;
03226   }
03227 
03228   /* Only the host is allowed to update the session desc */
03229   if( !This->dp2->bHostInterface )
03230   {
03231     return DPERR_ACCESSDENIED;
03232   }
03233 
03234   /* FIXME: Copy into This->dp2->lpSessionDesc */
03235   dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
03236   lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
03237 
03238   if( lpTempSessDesc == NULL )
03239   {
03240     return DPERR_OUTOFMEMORY;
03241   }
03242 
03243   /* Free the old */
03244   HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
03245 
03246   This->dp2->lpSessionDesc = lpTempSessDesc;
03247 
03248   /* Set the new */
03249   DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
03250 
03251   /* If this is an external invocation of the interface, we should be
03252    * letting everyone know that things have changed. Otherwise this is
03253    * just an initialization and it doesn't need to be propagated.
03254    */
03255   if( !bInitial )
03256   {
03257     FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
03258   }
03259 
03260   return DP_OK;
03261 }
03262 
03263 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
03264           ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
03265 {
03266   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03267   return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
03268 }
03269 
03270 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
03271           ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
03272 {
03273   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
03274   return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
03275 }
03276 
03277 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
03278 DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
03279 {
03280   DWORD dwSize = 0;
03281 
03282   if( lpSessDesc == NULL )
03283   {
03284     /* Hmmm..don't need any size? */
03285     ERR( "NULL lpSessDesc\n" );
03286     return dwSize;
03287   }
03288 
03289   dwSize += sizeof( *lpSessDesc );
03290 
03291   if( bAnsi )
03292   {
03293     if( lpSessDesc->lpszSessionNameA )
03294     {
03295       dwSize += lstrlenA( lpSessDesc->lpszSessionNameA ) + 1;
03296     }
03297 
03298     if( lpSessDesc->lpszPasswordA )
03299     {
03300       dwSize += lstrlenA( lpSessDesc->lpszPasswordA ) + 1;
03301     }
03302   }
03303   else /* UNICODE */
03304   {
03305     if( lpSessDesc->lpszSessionName )
03306     {
03307       dwSize += sizeof( WCHAR ) *
03308         ( lstrlenW( lpSessDesc->lpszSessionName ) + 1 );
03309     }
03310 
03311     if( lpSessDesc->lpszPassword )
03312     {
03313       dwSize += sizeof( WCHAR ) *
03314         ( lstrlenW( lpSessDesc->lpszPassword ) + 1 );
03315     }
03316   }
03317 
03318   return dwSize;
03319 }
03320 
03321 /* Assumes that contugous buffers are already allocated. */
03322 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
03323                                 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
03324 {
03325   BYTE* lpStartOfFreeSpace;
03326 
03327   if( lpSessionDest == NULL )
03328   {
03329     ERR( "NULL lpSessionDest\n" );
03330     return;
03331   }
03332 
03333   CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
03334 
03335   lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
03336 
03337   if( bAnsi )
03338   {
03339     if( lpSessionSrc->lpszSessionNameA )
03340     {
03341       lstrcpyA( (LPSTR)lpStartOfFreeSpace,
03342                 lpSessionDest->lpszSessionNameA );
03343       lpSessionDest->lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
03344       lpStartOfFreeSpace +=
03345         lstrlenA( (LPSTR)lpSessionDest->lpszSessionNameA ) + 1;
03346     }
03347 
03348     if( lpSessionSrc->lpszPasswordA )
03349     {
03350       lstrcpyA( (LPSTR)lpStartOfFreeSpace,
03351                 lpSessionDest->lpszPasswordA );
03352       lpSessionDest->lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
03353       lpStartOfFreeSpace +=
03354         lstrlenA( (LPSTR)lpSessionDest->lpszPasswordA ) + 1;
03355     }
03356   }
03357   else /* UNICODE */
03358   {
03359     if( lpSessionSrc->lpszSessionName )
03360     {
03361       lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
03362                 lpSessionDest->lpszSessionName );
03363       lpSessionDest->lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
03364       lpStartOfFreeSpace += sizeof(WCHAR) *
03365         ( lstrlenW( (LPWSTR)lpSessionDest->lpszSessionName ) + 1 );
03366     }
03367 
03368     if( lpSessionSrc->lpszPassword )
03369     {
03370       lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
03371                 lpSessionDest->lpszPassword );
03372       lpSessionDest->lpszPassword = (LPWSTR)lpStartOfFreeSpace;
03373       lpStartOfFreeSpace += sizeof(WCHAR) *
03374         ( lstrlenW( (LPWSTR)lpSessionDest->lpszPassword ) + 1 );
03375     }
03376   }
03377 }
03378 
03379 
03380 static HRESULT WINAPI DP_IF_AddGroupToGroup
03381           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
03382 {
03383   lpGroupData lpGParentData;
03384   lpGroupData lpGData;
03385   lpGroupList lpNewGList;
03386 
03387   TRACE( "(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
03388 
03389   if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
03390   {
03391     return DPERR_INVALIDGROUP;
03392   }
03393 
03394   if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
03395   {
03396     return DPERR_INVALIDGROUP;
03397   }
03398 
03399   /* Create a player list (ie "shortcut" ) */
03400   lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
03401   if( lpNewGList == NULL )
03402   {
03403     return DPERR_CANTADDPLAYER;
03404   }
03405 
03406   /* Add the shortcut */
03407   lpGData->uRef++;
03408   lpNewGList->lpGData = lpGData;
03409 
03410   /* Add the player to the list of players for this group */
03411   DPQ_INSERT( lpGData->groups, lpNewGList, groups );
03412 
03413   /* Send a ADDGROUPTOGROUP message */
03414   FIXME( "Not sending message\n" );
03415 
03416   return DP_OK;
03417 }
03418 
03419 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
03420           ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
03421 {
03422   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03423   return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
03424 }
03425 
03426 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
03427           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
03428 {
03429   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03430   return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
03431 }
03432 
03433 static HRESULT WINAPI DP_IF_CreateGroupInGroup
03434           ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
03435             LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
03436             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
03437 {
03438   lpGroupData lpGParentData;
03439   lpGroupList lpGList;
03440   lpGroupData lpGData;
03441 
03442   TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
03443          This, idParentGroup, lpidGroup, lpGroupName, lpData,
03444          dwDataSize, dwFlags, bAnsi );
03445 
03446   /* Verify that the specified parent is valid */
03447   if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
03448                                          idParentGroup ) ) == NULL
03449     )
03450   {
03451     return DPERR_INVALIDGROUP;
03452   }
03453 
03454   lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
03455                             dwFlags, idParentGroup, bAnsi );
03456 
03457   if( lpGData == NULL )
03458   {
03459     return DPERR_CANTADDPLAYER; /* yes player not group */
03460   }
03461 
03462   /* Something else is referencing this data */
03463   lpGData->uRef++;
03464 
03465   DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
03466 
03467   /* The list has now been inserted into the interface group list. We now
03468      need to put a "shortcut" to this group in the parent group */
03469   lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
03470   if( lpGList == NULL )
03471   {
03472     FIXME( "Memory leak\n" );
03473     return DPERR_CANTADDPLAYER; /* yes player not group */
03474   }
03475 
03476   lpGList->lpGData = lpGData;
03477 
03478   DPQ_INSERT( lpGParentData->groups, lpGList, groups );
03479 
03480   /* Let the SP know that we've created this group */
03481   if( This->dp2->spData.lpCB->CreateGroup )
03482   {
03483     DPSP_CREATEGROUPDATA data;
03484 
03485     TRACE( "Calling SP CreateGroup\n" );
03486 
03487     data.idGroup           = *lpidGroup;
03488     data.dwFlags           = dwFlags;
03489     data.lpSPMessageHeader = lpMsgHdr;
03490     data.lpISP             = This->dp2->spData.lpISP;
03491 
03492     (*This->dp2->spData.lpCB->CreateGroup)( &data );
03493   }
03494 
03495   /* Inform all other peers of the creation of a new group. If there are
03496    * no peers keep this quiet.
03497    */
03498   if( This->dp2->lpSessionDesc &&
03499       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
03500   {
03501     DPMSG_CREATEPLAYERORGROUP msg;
03502 
03503     msg.dwType = DPSYS_CREATEPLAYERORGROUP;
03504     msg.dwPlayerType = DPPLAYERTYPE_GROUP;
03505     msg.dpId = *lpidGroup;
03506     msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
03507     msg.lpData = lpData;
03508     msg.dwDataSize = dwDataSize;
03509     msg.dpnName = *lpGroupName;
03510 
03511     /* FIXME: Correct to just use send effectively? */
03512     /* FIXME: Should size include data w/ message or just message "header" */
03513     /* FIXME: Check return code */
03514     DP_SendEx( (IDirectPlay2Impl*)This,
03515                DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
03516                0, 0, NULL, NULL, bAnsi );
03517   }
03518 
03519   return DP_OK;
03520 }
03521 
03522 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
03523           ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
03524             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
03525             DWORD dwFlags )
03526 {
03527   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03528 
03529   *lpidGroup = DPID_UNKNOWN;
03530 
03531   return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
03532                                    lpGroupName, lpData, dwDataSize, dwFlags,
03533                                    TRUE );
03534 }
03535 
03536 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
03537           ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
03538             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
03539             DWORD dwFlags )
03540 {
03541   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03542 
03543   *lpidGroup = DPID_UNKNOWN;
03544 
03545   return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
03546                                    lpGroupName, lpData, dwDataSize,
03547                                    dwFlags, FALSE );
03548 }
03549 
03550 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
03551           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
03552 {
03553   lpGroupList lpGList;
03554   lpGroupData lpGParentData;
03555 
03556   TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
03557 
03558   /* Is the parent group valid? */
03559   if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
03560   {
03561     return DPERR_INVALIDGROUP;
03562   }
03563 
03564   /* Remove the group from the parent group queue */
03565   DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
03566 
03567   if( lpGList == NULL )
03568   {
03569     return DPERR_INVALIDGROUP;
03570   }
03571 
03572   /* Decrement the ref count */
03573   lpGList->lpGData->uRef--;
03574 
03575   /* Free up the list item */
03576   HeapFree( GetProcessHeap(), 0, lpGList );
03577 
03578   /* Should send a DELETEGROUPFROMGROUP message */
03579   FIXME( "message not sent\n" );
03580 
03581   return DP_OK;
03582 }
03583 
03584 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
03585           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
03586 {
03587   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03588   return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
03589 }
03590 
03591 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
03592           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
03593 {
03594   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03595   return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
03596 }
03597 
03598 static
03599 BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
03600                                     LPDWORD lpdwBufSize )
03601 {
03602   DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
03603   HRESULT                  hr;
03604 
03605   dpCompoundAddress.dwDataSize = sizeof( GUID );
03606   memcpy( &dpCompoundAddress.guidDataType, &DPAID_ServiceProvider,
03607           sizeof( GUID ) ) ;
03608   dpCompoundAddress.lpData = lpcSpGuid;
03609 
03610   *lplpAddrBuf = NULL;
03611   *lpdwBufSize = 0;
03612 
03613   hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
03614                                   lpdwBufSize, TRUE );
03615 
03616   if( hr != DPERR_BUFFERTOOSMALL )
03617   {
03618     ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
03619     return FALSE;
03620   }
03621 
03622   /* Now allocate the buffer */
03623   *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
03624                             *lpdwBufSize );
03625 
03626   hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
03627                                   lpdwBufSize, TRUE );
03628   if( FAILED(hr) )
03629   {
03630     ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
03631     return FALSE;
03632   }
03633 
03634   return TRUE;
03635 }
03636 
03637 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
03638           ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
03639 {
03640   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03641   TRACE("(%p)->(%p,%p,%p,0x%08lx)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
03642 
03643   /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
03644   if( dwFlags == 0 )
03645   {
03646     dwFlags = DPCONNECTION_DIRECTPLAY;
03647   }
03648 
03649   if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
03650           ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
03651     )
03652   {
03653     return DPERR_INVALIDFLAGS;
03654   }
03655 
03656   if( !lpEnumCallback || !*lpEnumCallback )
03657   {
03658      return DPERR_INVALIDPARAMS;
03659   }
03660 
03661   /* Enumerate DirectPlay service providers */
03662   if( dwFlags & DPCONNECTION_DIRECTPLAY )
03663   {
03664     HKEY hkResult;
03665     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
03666     LPCSTR guidDataSubKey  = "Guid";
03667     char subKeyName[51];
03668     DWORD dwIndex, sizeOfSubKeyName=50;
03669     FILETIME filetime;
03670 
03671     /* Need to loop over the service providers in the registry */
03672     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
03673                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
03674     {
03675       /* Hmmm. Does this mean that there are no service providers? */
03676       ERR(": no service providers?\n");
03677       return DP_OK;
03678     }
03679 
03680 
03681     /* Traverse all the service providers we have available */
03682     for( dwIndex=0;
03683          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
03684                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
03685          ++dwIndex, sizeOfSubKeyName=51 )
03686     {
03687 
03688       HKEY     hkServiceProvider;
03689       GUID     serviceProviderGUID;
03690       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
03691       char     returnBuffer[51];
03692       WCHAR    buff[51];
03693       DPNAME   dpName;
03694       BOOL     bBuildPass;
03695 
03696       LPVOID                   lpAddressBuffer = NULL;
03697       DWORD                    dwAddressBufferSize = 0;
03698 
03699       TRACE(" this time through: %s\n", subKeyName );
03700 
03701       /* Get a handle for this particular service provider */
03702       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
03703                          &hkServiceProvider ) != ERROR_SUCCESS )
03704       {
03705          ERR(": what the heck is going on?\n" );
03706          continue;
03707       }
03708 
03709       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
03710                             NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
03711                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
03712       {
03713         ERR(": missing GUID registry data members\n" );
03714         continue;
03715       }
03716 
03717       /* FIXME: Check return types to ensure we're interpreting data right */
03718       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
03719       CLSIDFromString( buff, &serviceProviderGUID );
03720       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
03721 
03722       /* Fill in the DPNAME struct for the service provider */
03723       dpName.dwSize             = sizeof( dpName );
03724       dpName.dwFlags            = 0;
03725       dpName.lpszShortNameA = subKeyName;
03726       dpName.lpszLongNameA  = NULL;
03727 
03728       /* Create the compound address for the service provider.
03729        * NOTE: This is a gruesome architectural scar right now.  DP
03730        * uses DPL and DPL uses DP.  Nasty stuff. This may be why the
03731        * native dll just gets around this little bit by allocating an
03732        * 80 byte buffer which isn't even filled with a valid compound
03733        * address. Oh well. Creating a proper compound address is the
03734        * way to go anyways despite this method taking slightly more
03735        * heap space and realtime :) */
03736 
03737       bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
03738                                            &lpAddressBuffer,
03739                                            &dwAddressBufferSize );
03740       if( !bBuildPass )
03741       {
03742         ERR( "Can't build compound addr\n" );
03743         return DPERR_GENERIC;
03744       }
03745 
03746       /* The enumeration will return FALSE if we are not to continue */
03747       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
03748                            &dpName, DPCONNECTION_DIRECTPLAY, lpContext ) )
03749       {
03750          return DP_OK;
03751       }
03752     }
03753   }
03754 
03755   /* Enumerate DirectPlayLobby service providers */
03756   if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
03757   {
03758     HKEY hkResult;
03759     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
03760     LPCSTR guidDataSubKey  = "Guid";
03761     char subKeyName[51];
03762     DWORD dwIndex, sizeOfSubKeyName=50;
03763     FILETIME filetime;
03764 
03765     /* Need to loop over the service providers in the registry */
03766     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
03767                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
03768     {
03769       /* Hmmm. Does this mean that there are no service providers? */
03770       ERR(": no service providers?\n");
03771       return DP_OK;
03772     }
03773 
03774 
03775     /* Traverse all the lobby providers we have available */
03776     for( dwIndex=0;
03777          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
03778                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
03779          ++dwIndex, sizeOfSubKeyName=51 )
03780     {
03781 
03782       HKEY     hkServiceProvider;
03783       GUID     serviceProviderGUID;
03784       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
03785       char     returnBuffer[51];
03786       WCHAR    buff[51];
03787       DPNAME   dpName;
03788       HRESULT  hr;
03789 
03790       DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
03791       LPVOID                   lpAddressBuffer = NULL;
03792       DWORD                    dwAddressBufferSize = 0;
03793 
03794       TRACE(" this time through: %s\n", subKeyName );
03795 
03796       /* Get a handle for this particular service provider */
03797       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
03798                          &hkServiceProvider ) != ERROR_SUCCESS )
03799       {
03800          ERR(": what the heck is going on?\n" );
03801          continue;
03802       }
03803 
03804       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
03805                             NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
03806                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
03807       {
03808         ERR(": missing GUID registry data members\n" );
03809         continue;
03810       }
03811 
03812       /* FIXME: Check return types to ensure we're interpreting data right */
03813       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
03814       CLSIDFromString( buff, &serviceProviderGUID );
03815       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
03816 
03817       /* Fill in the DPNAME struct for the service provider */
03818       dpName.dwSize             = sizeof( dpName );
03819       dpName.dwFlags            = 0;
03820       dpName.lpszShortNameA = subKeyName;
03821       dpName.lpszLongNameA  = NULL;
03822 
03823       /* Create the compound address for the service provider.
03824          NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
03825                nast stuff. This may be why the native dll just gets around this little bit by
03826                allocating an 80 byte buffer which isn't even a filled with a valid compound
03827                address. Oh well. Creating a proper compound address is the way to go anyways
03828                despite this method taking slightly more heap space and realtime :) */
03829 
03830       dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
03831       dpCompoundAddress.dwDataSize   = sizeof( GUID );
03832       dpCompoundAddress.lpData       = &serviceProviderGUID;
03833 
03834       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
03835                                      &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
03836       {
03837         ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
03838         return hr;
03839       }
03840 
03841       /* Now allocate the buffer */
03842       lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
03843 
03844       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
03845                                      &dwAddressBufferSize, TRUE ) ) != DP_OK )
03846       {
03847         ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
03848         return hr;
03849       }
03850 
03851       /* The enumeration will return FALSE if we are not to continue */
03852       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
03853                            &dpName, DPCONNECTION_DIRECTPLAYLOBBY, lpContext ) )
03854       {
03855          return DP_OK;
03856       }
03857     }
03858   }
03859 
03860   return DP_OK;
03861 }
03862 
03863 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
03864           ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
03865 {
03866   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03867   FIXME("(%p)->(%p,%p,%p,0x%08lx): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
03868   return DP_OK;
03869 }
03870 
03871 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
03872           ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
03873             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
03874             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
03875 {
03876   lpGroupList lpGList;
03877   lpGroupData lpGData;
03878 
03879   FIXME( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n",
03880          This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
03881          lpContext, dwFlags, bAnsi );
03882 
03883   if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
03884   {
03885     return DPERR_INVALIDGROUP;
03886   }
03887 
03888   if( DPQ_IS_EMPTY( lpGData->groups ) )
03889   {
03890     return DP_OK;
03891   }
03892 
03893   lpGList = DPQ_FIRST( lpGData->groups );
03894 
03895   for( ;; )
03896   {
03897     /* FIXME: Should check dwFlags for match here */
03898 
03899     if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
03900                                     &lpGList->lpGData->name, dwFlags,
03901                                     lpContext ) )
03902     {
03903       return DP_OK; /* User requested break */
03904     }
03905 
03906     if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
03907     {
03908       break;
03909     }
03910 
03911     lpGList = DPQ_NEXT( lpGList->groups );
03912 
03913   }
03914 
03915   return DP_OK;
03916 }
03917 
03918 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
03919           ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
03920             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
03921             DWORD dwFlags )
03922 {
03923   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03924   return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
03925                                   lpEnumPlayersCallback2, lpContext, dwFlags,
03926                                   TRUE );
03927 }
03928 
03929 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
03930           ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
03931             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
03932             DWORD dwFlags )
03933 {
03934   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03935   return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
03936                                   lpEnumPlayersCallback2, lpContext, dwFlags,
03937                                   FALSE );
03938 }
03939 
03940 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
03941           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
03942 {
03943   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03944   FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
03945   return DP_OK;
03946 }
03947 
03948 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
03949           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
03950 {
03951   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
03952   FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
03953   return DP_OK;
03954 }
03955 
03956 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
03957     REFGUID         guidDataType,
03958     DWORD           dwDataSize,
03959     LPCVOID         lpData,
03960     LPVOID          lpContext )
03961 {
03962   /* Looking for the GUID of the provider to load */
03963   if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
03964       ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
03965     )
03966   {
03967     TRACE( "Found SP/LP (%s) %s (data size = 0x%08lx)\n",
03968            debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
03969 
03970     if( dwDataSize != sizeof( GUID ) )
03971     {
03972       ERR( "Invalid sp/lp guid size 0x%08lx\n", dwDataSize );
03973     }
03974 
03975     memcpy( lpContext, lpData, dwDataSize );
03976 
03977     /* There shouldn't be more than 1 GUID/compound address */
03978     return FALSE;
03979   }
03980 
03981   /* Still waiting for what we want */
03982   return TRUE;
03983 }
03984 
03985 
03986 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
03987 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
03988 {
03989   UINT i;
03990   LPCSTR spSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
03991   LPCSTR lpSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
03992   LPCSTR guidDataSubKey   = "Guid";
03993   LPCSTR majVerDataSubKey = "dwReserved1";
03994   LPCSTR minVerDataSubKey = "dwReserved2";
03995   LPCSTR pathSubKey       = "Path";
03996 
03997   TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
03998 
03999   /* FIXME: Cloned code with a quick hack. */
04000   for( i=0; i<2; i++ )
04001   {
04002     HKEY hkResult;
04003     LPCSTR searchSubKey;
04004     char subKeyName[51];
04005     DWORD dwIndex, sizeOfSubKeyName=50;
04006     FILETIME filetime;
04007 
04008     (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
04009     *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
04010 
04011 
04012     /* Need to loop over the service providers in the registry */
04013     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
04014                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
04015     {
04016       /* Hmmm. Does this mean that there are no service providers? */
04017       ERR(": no service providers?\n");
04018       return 0;
04019     }
04020 
04021     /* Traverse all the service providers we have available */
04022     for( dwIndex=0;
04023          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
04024                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
04025          ++dwIndex, sizeOfSubKeyName=51 )
04026     {
04027 
04028       HKEY     hkServiceProvider;
04029       GUID     serviceProviderGUID;
04030       DWORD    returnType, sizeOfReturnBuffer = 255;
04031       char     returnBuffer[256];
04032       WCHAR    buff[51];
04033       DWORD    dwTemp, len;
04034 
04035       TRACE(" this time through: %s\n", subKeyName );
04036 
04037       /* Get a handle for this particular service provider */
04038       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
04039                          &hkServiceProvider ) != ERROR_SUCCESS )
04040       {
04041          ERR(": what the heck is going on?\n" );
04042          continue;
04043       }
04044 
04045       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
04046                             NULL, &returnType, (LPBYTE)returnBuffer,
04047                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
04048       {
04049         ERR(": missing GUID registry data members\n" );
04050         continue;
04051       }
04052 
04053       /* FIXME: Check return types to ensure we're interpreting data right */
04054       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
04055       CLSIDFromString( buff, &serviceProviderGUID );
04056       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
04057 
04058       /* Determine if this is the Service Provider that the user asked for */
04059       if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
04060       {
04061         continue;
04062       }
04063 
04064       if( i == 0 ) /* DP SP */
04065       {
04066         len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
04067         lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
04068         MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
04069       }
04070 
04071       sizeOfReturnBuffer = 255;
04072 
04073       /* Get dwReserved1 */
04074       if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
04075                             NULL, &returnType, (LPBYTE)returnBuffer,
04076                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
04077       {
04078          ERR(": missing dwReserved1 registry data members\n") ;
04079          continue;
04080       }
04081 
04082       if( i == 0 )
04083           memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
04084 
04085       sizeOfReturnBuffer = 255;
04086 
04087       /* Get dwReserved2 */
04088       if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
04089                             NULL, &returnType, (LPBYTE)returnBuffer,
04090                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
04091       {
04092          ERR(": missing dwReserved1 registry data members\n") ;
04093          continue;
04094       }
04095 
04096       if( i == 0 )
04097           memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
04098 
04099       sizeOfReturnBuffer = 255;
04100 
04101       /* Get the path for this service provider */
04102       if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
04103                             NULL, NULL, (LPBYTE)returnBuffer,
04104                             &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
04105       {
04106         ERR(": missing PATH registry data members: 0x%08lx\n", dwTemp );
04107         continue;
04108       }
04109 
04110       TRACE( "Loading %s\n", returnBuffer );
04111       return LoadLibraryA( returnBuffer );
04112     }
04113   }
04114 
04115   return 0;
04116 }
04117 
04118 static
04119 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
04120 {
04121   HRESULT hr;
04122   LPDPSP_SPINIT SPInit;
04123 
04124   /* Initialize the service provider by calling SPInit */
04125   SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
04126 
04127   if( SPInit == NULL )
04128   {
04129     ERR( "Service provider doesn't provide SPInit interface?\n" );
04130     FreeLibrary( hServiceProvider );
04131     return DPERR_UNAVAILABLE;
04132   }
04133 
04134   TRACE( "Calling SPInit (DP SP entry point)\n" );
04135 
04136   hr = (*SPInit)( &This->dp2->spData );
04137 
04138   if( FAILED(hr) )
04139   {
04140     ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
04141     FreeLibrary( hServiceProvider );
04142     return hr;
04143   }
04144 
04145   /* FIXME: Need to verify the sanity of the returned callback table
04146    *        using IsBadCodePtr */
04147   This->dp2->bSPInitialized = TRUE;
04148 
04149   /* This interface is now initialized as a DP object */
04150   This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
04151 
04152   /* Store the handle of the module so that we can unload it later */
04153   This->dp2->hServiceProvider = hServiceProvider;
04154 
04155   return hr;
04156 }
04157 
04158 static
04159 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
04160 {
04161   HRESULT hr;
04162   LPSP_INIT DPLSPInit;
04163 
04164   /* Initialize the service provider by calling SPInit */
04165   DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
04166 
04167   if( DPLSPInit == NULL )
04168   {
04169     ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
04170     FreeLibrary( hLobbyProvider );
04171     return DPERR_UNAVAILABLE;
04172   }
04173 
04174   TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
04175 
04176   hr = (*DPLSPInit)( &This->dp2->dplspData );
04177 
04178   if( FAILED(hr) )
04179   {
04180     ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
04181     FreeLibrary( hLobbyProvider );
04182     return hr;
04183   }
04184 
04185   /* FIXME: Need to verify the sanity of the returned callback table
04186    *        using IsBadCodePtr */
04187 
04188   This->dp2->bDPLSPInitialized = TRUE;
04189 
04190   /* This interface is now initialized as a lobby object */
04191   This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
04192 
04193   /* Store the handle of the module so that we can unload it later */
04194   This->dp2->hDPLobbyProvider = hLobbyProvider;
04195 
04196   return hr;
04197 }
04198 
04199 static HRESULT WINAPI DP_IF_InitializeConnection
04200           ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
04201 {
04202   HMODULE hServiceProvider;
04203   HRESULT hr;
04204   GUID guidSP;
04205   const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
04206   BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
04207 
04208   TRACE("(%p)->(%p,0x%08lx,%u)\n", This, lpConnection, dwFlags, bAnsi );
04209 
04210   if( dwFlags != 0 )
04211   {
04212     return DPERR_INVALIDFLAGS;
04213   }
04214 
04215   /* Find out what the requested SP is and how large this buffer is */
04216   hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
04217                         dwAddrSize, &guidSP );
04218 
04219   if( FAILED(hr) )
04220   {
04221     ERR( "Invalid compound address?\n" );
04222     return DPERR_UNAVAILABLE;
04223   }
04224 
04225   /* Load the service provider */
04226   hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
04227 
04228   if( hServiceProvider == 0 )
04229   {
04230     ERR( "Unable to load service provider\n" );
04231     return DPERR_UNAVAILABLE;
04232   }
04233 
04234   if( bIsDpSp )
04235   {
04236      /* Fill in what we can of the Service Provider required information.
04237       * The rest was be done in DP_LoadSP
04238       */
04239      This->dp2->spData.lpAddress = lpConnection;
04240      This->dp2->spData.dwAddressSize = dwAddrSize;
04241      This->dp2->spData.lpGuid = &guidSP;
04242 
04243      hr = DP_InitializeDPSP( This, hServiceProvider );
04244   }
04245   else
04246   {
04247      This->dp2->dplspData.lpAddress = lpConnection;
04248 
04249      hr = DP_InitializeDPLSP( This, hServiceProvider );
04250   }
04251 
04252   if( FAILED(hr) )
04253   {
04254     return hr;
04255   }
04256 
04257   return DP_OK;
04258 }
04259 
04260 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
04261           ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
04262 {
04263   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04264 
04265   /* This may not be externally invoked once either an SP or LP is initialized */
04266   if( This->dp2->connectionInitialized != NO_PROVIDER )
04267   {
04268     return DPERR_ALREADYINITIALIZED;
04269   }
04270 
04271   return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
04272 }
04273 
04274 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
04275           ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
04276 {
04277   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04278 
04279   /* This may not be externally invoked once either an SP or LP is initialized */
04280   if( This->dp2->connectionInitialized != NO_PROVIDER )
04281   {
04282     return DPERR_ALREADYINITIALIZED;
04283   }
04284 
04285   return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
04286 }
04287 
04288 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
04289           ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
04290             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
04291 {
04292   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
04293   return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
04294 }
04295 
04296 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
04297           ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
04298             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
04299 {
04300   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
04301   return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
04302 }
04303 
04304 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
04305           ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
04306 {
04307   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04308   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
04309   return DP_OK;
04310 }
04311 
04312 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
04313           ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
04314 {
04315   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04316   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
04317   return DP_OK;
04318 }
04319 
04320 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
04321           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
04322 {
04323   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04324   FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection );
04325   return DP_OK;
04326 }
04327 
04328 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
04329           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
04330 {
04331   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04332   FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection );
04333   return DP_OK;
04334 }
04335 
04336 static HRESULT WINAPI DirectPlay3AImpl_StartSession
04337           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
04338 {
04339   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04340   FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup );
04341   return DP_OK;
04342 }
04343 
04344 static HRESULT WINAPI DirectPlay3WImpl_StartSession
04345           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
04346 {
04347   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04348   FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup );
04349   return DP_OK;
04350 }
04351 
04352 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
04353           ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
04354 {
04355   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04356   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags );
04357   return DP_OK;
04358 }
04359 
04360 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
04361           ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
04362 {
04363   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04364   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags );
04365   return DP_OK;
04366 }
04367 
04368 static HRESULT WINAPI DP_IF_GetGroupParent
04369           ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
04370             BOOL bAnsi )
04371 {
04372   lpGroupData lpGData;
04373 
04374   TRACE("(%p)->(0x%08lx,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
04375 
04376   if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
04377   {
04378     return DPERR_INVALIDGROUP;
04379   }
04380 
04381   *lpidGroup = lpGData->dpid;
04382 
04383   return DP_OK;
04384 }
04385 
04386 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
04387           ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
04388 {
04389   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04390   return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
04391 }
04392 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
04393           ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
04394 {
04395   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04396   return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
04397 }
04398 
04399 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
04400           ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
04401 {
04402   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04403   FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
04404   return DP_OK;
04405 }
04406 
04407 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
04408           ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
04409 {
04410   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04411   FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
04412   return DP_OK;
04413 }
04414 
04415 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
04416           ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
04417 {
04418   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04419   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags );
04420   return DP_OK;
04421 }
04422 
04423 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
04424           ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
04425 {
04426   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
04427   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags );
04428   return DP_OK;
04429 }
04430 
04431 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
04432           ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
04433 {
04434   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
04435   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner );
04436   return DP_OK;
04437 }
04438 
04439 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
04440           ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
04441 {
04442   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
04443   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner );
04444   return DP_OK;
04445 }
04446 
04447 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
04448           ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
04449 {
04450   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
04451   FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner );
04452   return DP_OK;
04453 }
04454 
04455 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
04456           ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
04457 {
04458   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
04459   FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner );
04460   return DP_OK;
04461 }
04462 
04463 static HRESULT WINAPI DP_SendEx
04464           ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
04465             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
04466             LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
04467 {
04468   lpPlayerList lpPList;
04469   lpGroupData  lpGData;
04470   BOOL         bValidDestination = FALSE;
04471 
04472   FIXME( "(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx,0x%08lx,0x%08lx,%p,%p,%u)"
04473          ": stub\n",
04474          This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
04475          dwTimeout, lpContext, lpdwMsgID, bAnsi );
04476 
04477   /* FIXME: Add parameter checking */
04478   /* FIXME: First call to this needs to aquire a message id which will be
04479    *        used for multiple sends
04480    */
04481 
04482   /* NOTE: Can't send messages to yourself - this will be trapped in receive */
04483 
04484   /* Verify that the message is being sent from a valid local player. The
04485    * from player may be anonymous DPID_UNKNOWN
04486    */
04487   if( idFrom != DPID_UNKNOWN )
04488   {
04489     if( ( lpPList = DP_FindPlayer( This, idFrom ) ) == NULL )
04490     {
04491       WARN( "INFO: Invalid from player 0x%08lx\n", idFrom );
04492       return DPERR_INVALIDPLAYER;
04493     }
04494   }
04495 
04496   /* Verify that the message is being sent to a valid player, group or to
04497    * everyone. If it's valid, send it to those players.
04498    */
04499   if( idTo == DPID_ALLPLAYERS )
04500   {
04501     bValidDestination = TRUE;
04502 
04503     /* See if SP has the ability to multicast. If so, use it */
04504     if( This->dp2->spData.lpCB->SendToGroupEx )
04505     {
04506       FIXME( "Use group sendex to group 0\n" );
04507     }
04508     else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
04509     {
04510       FIXME( "Use obsolete group send to group 0\n" );
04511     }
04512     else /* No multicast, multiplicate */
04513     {
04514       /* Send to all players we know about */
04515       FIXME( "Send to all players using EnumPlayersInGroup\n" );
04516     }
04517   }
04518 
04519   if( ( !bValidDestination ) &&
04520       ( DP_FindPlayer( This, idTo ) != NULL )
04521     )
04522   {
04523     bValidDestination = TRUE;
04524 
04525     /* Have the service provider send this message */
04526     /* FIXME: Could optimize for local interface sends */
04527     return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
04528                          dwTimeout, lpContext, lpdwMsgID );
04529   }
04530 
04531   if( ( !bValidDestination ) &&
04532       ( ( lpGData = DP_FindAnyGroup( This, idTo ) ) != NULL )
04533     )
04534   {
04535     bValidDestination = TRUE;
04536 
04537     /* See if SP has the ability to multicast. If so, use it */
04538     if( This->dp2->spData.lpCB->SendToGroupEx )
04539     {
04540       FIXME( "Use group sendex\n" );
04541     }
04542     else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
04543     {
04544       FIXME( "Use obsolete group send to group\n" );
04545     }
04546     else /* No multicast, multiplicate */
04547     {
04548       FIXME( "Send to all players using EnumPlayersInGroup\n" );
04549     }
04550 
04551 #if 0
04552     if( bExpectReply )
04553     {
04554       DWORD dwWaitReturn;
04555 
04556       This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
04557 
04558       dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
04559       if( dwWaitReturn != WAIT_OBJECT_0 )
04560       {
04561         ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
04562       }
04563     }
04564 #endif
04565   }
04566 
04567   if( !bValidDestination )
04568   {
04569     return DPERR_INVALIDPLAYER;
04570   }
04571   else
04572   {
04573     /* FIXME: Should return what the send returned */
04574     return DP_OK;
04575   }
04576 }
04577 
04578 
04579 static HRESULT WINAPI DirectPlay4AImpl_SendEx
04580           ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
04581             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
04582             LPVOID lpContext, LPDWORD lpdwMsgID )
04583 {
04584   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
04585   return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
04586                     dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
04587 }
04588 
04589 static HRESULT WINAPI DirectPlay4WImpl_SendEx
04590           ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
04591             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
04592             LPVOID lpContext, LPDWORD lpdwMsgID )
04593 {
04594   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
04595   return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
04596                     dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
04597 }
04598 
04599 static HRESULT WINAPI DP_SP_SendEx
04600           ( IDirectPlay2Impl* This, DWORD dwFlags,
04601             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
04602             LPVOID lpContext, LPDWORD lpdwMsgID )
04603 {
04604   LPDPMSG lpMElem;
04605 
04606   FIXME( ": stub\n" );
04607 
04608   /* FIXME: This queuing should only be for async messages */
04609 
04610   lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
04611   lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
04612 
04613   CopyMemory( lpMElem->msg, lpData, dwDataSize );
04614 
04615   /* FIXME: Need to queue based on priority */
04616   DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
04617 
04618   return DP_OK;
04619 }
04620 
04621 static HRESULT WINAPI DP_IF_GetMessageQueue
04622           ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
04623             LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
04624 {
04625   HRESULT hr = DP_OK;
04626 
04627   FIXME( "(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,%p,%u): semi stub\n",
04628          This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
04629 
04630   /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
04631   /* FIXME: What about sends which are not immediate? */
04632 
04633   if( This->dp2->spData.lpCB->GetMessageQueue )
04634   {
04635     DPSP_GETMESSAGEQUEUEDATA data;
04636 
04637     FIXME( "Calling SP GetMessageQueue - is it right?\n" );
04638 
04639     /* FIXME: None of this is documented :( */
04640 
04641     data.lpISP        = This->dp2->spData.lpISP;
04642     data.dwFlags      = dwFlags;
04643     data.idFrom       = idFrom;
04644     data.idTo         = idTo;
04645     data.lpdwNumMsgs  = lpdwNumMsgs;
04646     data.lpdwNumBytes = lpdwNumBytes;
04647 
04648     hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
04649   }
04650   else
04651   {
04652     FIXME( "No SP for GetMessageQueue - fake some data\n" );
04653   }
04654 
04655   return hr;
04656 }
04657 
04658 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
04659           ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
04660             LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
04661 {
04662   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
04663   return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
04664                                 lpdwNumBytes, TRUE );
04665 }
04666 
04667 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
04668           ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
04669             LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
04670 {
04671   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
04672   return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
04673                                 lpdwNumBytes, FALSE );
04674 }
04675 
04676 static HRESULT WINAPI DP_IF_CancelMessage
04677           ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
04678             DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
04679 {
04680   HRESULT hr = DP_OK;
04681 
04682   FIXME( "(%p)->(0x%08lx,0x%08lx,%u): semi stub\n",
04683          This, dwMsgID, dwFlags, bAnsi );
04684 
04685   if( This->dp2->spData.lpCB->Cancel )
04686   {
04687     DPSP_CANCELDATA data;
04688 
04689     TRACE( "Calling SP Cancel\n" );
04690 
04691     /* FIXME: Undocumented callback */
04692 
04693     data.lpISP          = This->dp2->spData.lpISP;
04694     data.dwFlags        = dwFlags;
04695     data.lprglpvSPMsgID = NULL;
04696     data.cSPMsgID       = dwMsgID;
04697     data.dwMinPriority  = dwMinPriority;
04698     data.dwMaxPriority  = dwMaxPriority;
04699 
04700     hr = (*This->dp2->spData.lpCB->Cancel)( &data );
04701   }
04702   else
04703   {
04704     FIXME( "SP doesn't implement Cancel\n" );
04705   }
04706 
04707   return hr;
04708 }
04709 
04710 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
04711           ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
04712 {
04713   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
04714 
04715   if( dwFlags != 0 )
04716   {
04717     return DPERR_INVALIDFLAGS;
04718   }
04719 
04720   if( dwMsgID == 0 )
04721   {
04722     dwFlags |= DPCANCELSEND_ALL;
04723   }
04724 
04725   return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
04726 }
04727 
04728 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
04729           ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
04730 {
04731   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
04732 
04733   if( dwFlags != 0 )
04734   {
04735     return DPERR_INVALIDFLAGS;
04736   }
04737 
04738   if( dwMsgID == 0 )
04739   {
04740     dwFlags |= DPCANCELSEND_ALL;
04741   }
04742 
04743   return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
04744 }
04745 
04746 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
04747           ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
04748             DWORD dwFlags )
04749 {
04750   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
04751 
04752   if( dwFlags != 0 )
04753   {
04754     return DPERR_INVALIDFLAGS;
04755   }
04756 
04757   return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
04758                               dwMaxPriority, TRUE );
04759 }
04760 
04761 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
04762           ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
04763             DWORD dwFlags )
04764 {
04765   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
04766 
04767   if( dwFlags != 0 )
04768   {
04769     return DPERR_INVALIDFLAGS;
04770   }
04771 
04772   return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
04773                               dwMaxPriority, FALSE );
04774 }
04775 
04776 /* Note: Hack so we can reuse the old functions without compiler warnings */
04777 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
04778 # define XCAST(fun)     (typeof(directPlay2WVT.fun))
04779 #else
04780 # define XCAST(fun)     (void*)
04781 #endif
04782 
04783 static const IDirectPlay2Vtbl directPlay2WVT =
04784 {
04785   XCAST(QueryInterface)DP_QueryInterface,
04786   XCAST(AddRef)DP_AddRef,
04787   XCAST(Release)DP_Release,
04788 
04789   DirectPlay2WImpl_AddPlayerToGroup,
04790   DirectPlay2WImpl_Close,
04791   DirectPlay2WImpl_CreateGroup,
04792   DirectPlay2WImpl_CreatePlayer,
04793   DirectPlay2WImpl_DeletePlayerFromGroup,
04794   DirectPlay2WImpl_DestroyGroup,
04795   DirectPlay2WImpl_DestroyPlayer,
04796   DirectPlay2WImpl_EnumGroupPlayers,
04797   DirectPlay2WImpl_EnumGroups,
04798   DirectPlay2WImpl_EnumPlayers,
04799   DirectPlay2WImpl_EnumSessions,
04800   DirectPlay2WImpl_GetCaps,
04801   DirectPlay2WImpl_GetGroupData,
04802   DirectPlay2WImpl_GetGroupName,
04803   DirectPlay2WImpl_GetMessageCount,
04804   DirectPlay2WImpl_GetPlayerAddress,
04805   DirectPlay2WImpl_GetPlayerCaps,
04806   DirectPlay2WImpl_GetPlayerData,
04807   DirectPlay2WImpl_GetPlayerName,
04808   DirectPlay2WImpl_GetSessionDesc,
04809   DirectPlay2WImpl_Initialize,
04810   DirectPlay2WImpl_Open,
04811   DirectPlay2WImpl_Receive,
04812   DirectPlay2WImpl_Send,
04813   DirectPlay2WImpl_SetGroupData,
04814   DirectPlay2WImpl_SetGroupName,
04815   DirectPlay2WImpl_SetPlayerData,
04816   DirectPlay2WImpl_SetPlayerName,
04817   DirectPlay2WImpl_SetSessionDesc
04818 };
04819 #undef XCAST
04820 
04821 /* Note: Hack so we can reuse the old functions without compiler warnings */
04822 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
04823 # define XCAST(fun)     (typeof(directPlay2AVT.fun))
04824 #else
04825 # define XCAST(fun)     (void*)
04826 #endif
04827 
04828 static const IDirectPlay2Vtbl directPlay2AVT =
04829 {
04830   XCAST(QueryInterface)DP_QueryInterface,
04831   XCAST(AddRef)DP_AddRef,
04832   XCAST(Release)DP_Release,
04833 
04834   DirectPlay2AImpl_AddPlayerToGroup,
04835   DirectPlay2AImpl_Close,
04836   DirectPlay2AImpl_CreateGroup,
04837   DirectPlay2AImpl_CreatePlayer,
04838   DirectPlay2AImpl_DeletePlayerFromGroup,
04839   DirectPlay2AImpl_DestroyGroup,
04840   DirectPlay2AImpl_DestroyPlayer,
04841   DirectPlay2AImpl_EnumGroupPlayers,
04842   DirectPlay2AImpl_EnumGroups,
04843   DirectPlay2AImpl_EnumPlayers,
04844   DirectPlay2AImpl_EnumSessions,
04845   DirectPlay2AImpl_GetCaps,
04846   DirectPlay2AImpl_GetGroupData,
04847   DirectPlay2AImpl_GetGroupName,
04848   DirectPlay2AImpl_GetMessageCount,
04849   DirectPlay2AImpl_GetPlayerAddress,
04850   DirectPlay2AImpl_GetPlayerCaps,
04851   DirectPlay2AImpl_GetPlayerData,
04852   DirectPlay2AImpl_GetPlayerName,
04853   DirectPlay2AImpl_GetSessionDesc,
04854   DirectPlay2AImpl_Initialize,
04855   DirectPlay2AImpl_Open,
04856   DirectPlay2AImpl_Receive,
04857   DirectPlay2AImpl_Send,
04858   DirectPlay2AImpl_SetGroupData,
04859   DirectPlay2AImpl_SetGroupName,
04860   DirectPlay2AImpl_SetPlayerData,
04861   DirectPlay2AImpl_SetPlayerName,
04862   DirectPlay2AImpl_SetSessionDesc
04863 };
04864 #undef XCAST
04865 
04866 
04867 /* Note: Hack so we can reuse the old functions without compiler warnings */
04868 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
04869 # define XCAST(fun)     (typeof(directPlay3AVT.fun))
04870 #else
04871 # define XCAST(fun)     (void*)
04872 #endif
04873 
04874 static const IDirectPlay3Vtbl directPlay3AVT =
04875 {
04876   XCAST(QueryInterface)DP_QueryInterface,
04877   XCAST(AddRef)DP_AddRef,
04878   XCAST(Release)DP_Release,
04879 
04880   XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
04881   XCAST(Close)DirectPlay2AImpl_Close,
04882   XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
04883   XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
04884   XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
04885   XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
04886   XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
04887   XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
04888   XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
04889   XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
04890   XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
04891   XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
04892   XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
04893   XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
04894   XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
04895   XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
04896   XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
04897   XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
04898   XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
04899   XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
04900   XCAST(Initialize)DirectPlay2AImpl_Initialize,
04901   XCAST(Open)DirectPlay2AImpl_Open,
04902   XCAST(Receive)DirectPlay2AImpl_Receive,
04903   XCAST(Send)DirectPlay2AImpl_Send,
04904   XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
04905   XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
04906   XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
04907   XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
04908   XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
04909 
04910   DirectPlay3AImpl_AddGroupToGroup,
04911   DirectPlay3AImpl_CreateGroupInGroup,
04912   DirectPlay3AImpl_DeleteGroupFromGroup,
04913   DirectPlay3AImpl_EnumConnections,
04914   DirectPlay3AImpl_EnumGroupsInGroup,
04915   DirectPlay3AImpl_GetGroupConnectionSettings,
04916   DirectPlay3AImpl_InitializeConnection,
04917   DirectPlay3AImpl_SecureOpen,
04918   DirectPlay3AImpl_SendChatMessage,
04919   DirectPlay3AImpl_SetGroupConnectionSettings,
04920   DirectPlay3AImpl_StartSession,
04921   DirectPlay3AImpl_GetGroupFlags,
04922   DirectPlay3AImpl_GetGroupParent,
04923   DirectPlay3AImpl_GetPlayerAccount,
04924   DirectPlay3AImpl_GetPlayerFlags
04925 };
04926 #undef XCAST
04927 
04928 /* Note: Hack so we can reuse the old functions without compiler warnings */
04929 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
04930 # define XCAST(fun)     (typeof(directPlay3WVT.fun))
04931 #else
04932 # define XCAST(fun)     (void*)
04933 #endif
04934 static const IDirectPlay3Vtbl directPlay3WVT =
04935 {
04936   XCAST(QueryInterface)DP_QueryInterface,
04937   XCAST(AddRef)DP_AddRef,
04938   XCAST(Release)DP_Release,
04939 
04940   XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
04941   XCAST(Close)DirectPlay2WImpl_Close,
04942   XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
04943   XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
04944   XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
04945   XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
04946   XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
04947   XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
04948   XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
04949   XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
04950   XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
04951   XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
04952   XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
04953   XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
04954   XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
04955   XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
04956   XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
04957   XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
04958   XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
04959   XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
04960   XCAST(Initialize)DirectPlay2WImpl_Initialize,
04961   XCAST(Open)DirectPlay2WImpl_Open,
04962   XCAST(Receive)DirectPlay2WImpl_Receive,
04963   XCAST(Send)DirectPlay2WImpl_Send,
04964   XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
04965   XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
04966   XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
04967   XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
04968   XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
04969 
04970   DirectPlay3WImpl_AddGroupToGroup,
04971   DirectPlay3WImpl_CreateGroupInGroup,
04972   DirectPlay3WImpl_DeleteGroupFromGroup,
04973   DirectPlay3WImpl_EnumConnections,
04974   DirectPlay3WImpl_EnumGroupsInGroup,
04975   DirectPlay3WImpl_GetGroupConnectionSettings,
04976   DirectPlay3WImpl_InitializeConnection,
04977   DirectPlay3WImpl_SecureOpen,
04978   DirectPlay3WImpl_SendChatMessage,
04979   DirectPlay3WImpl_SetGroupConnectionSettings,
04980   DirectPlay3WImpl_StartSession,
04981   DirectPlay3WImpl_GetGroupFlags,
04982   DirectPlay3WImpl_GetGroupParent,
04983   DirectPlay3WImpl_GetPlayerAccount,
04984   DirectPlay3WImpl_GetPlayerFlags
04985 };
04986 #undef XCAST
04987 
04988 /* Note: Hack so we can reuse the old functions without compiler warnings */
04989 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
04990 # define XCAST(fun)     (typeof(directPlay4WVT.fun))
04991 #else
04992 # define XCAST(fun)     (void*)
04993 #endif
04994 static const IDirectPlay4Vtbl directPlay4WVT =
04995 {
04996   XCAST(QueryInterface)DP_QueryInterface,
04997   XCAST(AddRef)DP_AddRef,
04998   XCAST(Release)DP_Release,
04999 
05000   XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
05001   XCAST(Close)DirectPlay2WImpl_Close,
05002   XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
05003   XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
05004   XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
05005   XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
05006   XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
05007   XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
05008   XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
05009   XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
05010   XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
05011   XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
05012   XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
05013   XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
05014   XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
05015   XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
05016   XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
05017   XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
05018   XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
05019   XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
05020   XCAST(Initialize)DirectPlay2WImpl_Initialize,
05021   XCAST(Open)DirectPlay2WImpl_Open,
05022   XCAST(Receive)DirectPlay2WImpl_Receive,
05023   XCAST(Send)DirectPlay2WImpl_Send,
05024   XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
05025   XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
05026   XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
05027   XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
05028   XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
05029 
05030   XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
05031   XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
05032   XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
05033   XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
05034   XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
05035   XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
05036   XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
05037   XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
05038   XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
05039   XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
05040   XCAST(StartSession)DirectPlay3WImpl_StartSession,
05041   XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
05042   XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
05043   XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
05044   XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
05045 
05046   DirectPlay4WImpl_GetGroupOwner,
05047   DirectPlay4WImpl_SetGroupOwner,
05048   DirectPlay4WImpl_SendEx,
05049   DirectPlay4WImpl_GetMessageQueue,
05050   DirectPlay4WImpl_CancelMessage,
05051   DirectPlay4WImpl_CancelPriority
05052 };
05053 #undef XCAST
05054 
05055 
05056 /* Note: Hack so we can reuse the old functions without compiler warnings */
05057 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
05058 # define XCAST(fun)     (typeof(directPlay4AVT.fun))
05059 #else
05060 # define XCAST(fun)     (void*)
05061 #endif
05062 static const IDirectPlay4Vtbl directPlay4AVT =
05063 {
05064   XCAST(QueryInterface)DP_QueryInterface,
05065   XCAST(AddRef)DP_AddRef,
05066   XCAST(Release)DP_Release,
05067 
05068   XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
05069   XCAST(Close)DirectPlay2AImpl_Close,
05070   XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
05071   XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
05072   XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
05073   XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
05074   XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
05075   XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
05076   XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
05077   XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
05078   XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
05079   XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
05080   XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
05081   XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
05082   XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
05083   XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
05084   XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
05085   XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
05086   XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
05087   XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
05088   XCAST(Initialize)DirectPlay2AImpl_Initialize,
05089   XCAST(Open)DirectPlay2AImpl_Open,
05090   XCAST(Receive)DirectPlay2AImpl_Receive,
05091   XCAST(Send)DirectPlay2AImpl_Send,
05092   XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
05093   XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
05094   XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
05095   XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
05096   XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
05097 
05098   XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
05099   XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
05100   XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
05101   XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
05102   XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
05103   XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
05104   XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
05105   XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
05106   XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
05107   XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
05108   XCAST(StartSession)DirectPlay3AImpl_StartSession,
05109   XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
05110   XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
05111   XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
05112   XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
05113 
05114   DirectPlay4AImpl_GetGroupOwner,
05115   DirectPlay4AImpl_SetGroupOwner,
05116   DirectPlay4AImpl_SendEx,
05117   DirectPlay4AImpl_GetMessageQueue,
05118   DirectPlay4AImpl_CancelMessage,
05119   DirectPlay4AImpl_CancelPriority
05120 };
05121 #undef XCAST
05122 
05123 extern
05124 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
05125                             DPID idPlayer,
05126                             LPVOID* lplpData )
05127 {
05128   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
05129 
05130   if( lpPlayer == NULL )
05131   {
05132     return DPERR_INVALIDPLAYER;
05133   }
05134 
05135   *lplpData = lpPlayer->lpPData->lpSPPlayerData;
05136 
05137   return DP_OK;
05138 }
05139 
05140 extern
05141 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
05142                             DPID idPlayer,
05143                             LPVOID lpData )
05144 {
05145   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
05146 
05147   if( lpPlayer == NULL )
05148   {
05149     return DPERR_INVALIDPLAYER;
05150   }
05151 
05152   lpPlayer->lpPData->lpSPPlayerData = lpData;
05153 
05154   return DP_OK;
05155 }
05156 
05157 /***************************************************************************
05158  *  DirectPlayEnumerateAW
05159  *
05160  *  The pointer to the structure lpContext will be filled with the
05161  *  appropriate data for each service offered by the OS. These services are
05162  *  not necessarily available on this particular machine but are defined
05163  *  as simple service providers under the "Service Providers" registry key.
05164  *  This structure is then passed to lpEnumCallback for each of the different
05165  *  services.
05166  *
05167  *  This API is useful only for applications written using DirectX3 or
05168  *  worse. It is superseded by IDirectPlay3::EnumConnections which also
05169  *  gives information on the actual connections.
05170  *
05171  * defn of a service provider:
05172  * A dynamic-link library used by DirectPlay to communicate over a network.
05173  * The service provider contains all the network-specific code required
05174  * to send and receive messages. Online services and network operators can
05175  * supply service providers to use specialized hardware, protocols, communications
05176  * media, and network resources.
05177  *
05178  */
05179 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
05180                                      LPDPENUMDPCALLBACKW lpEnumCallbackW,
05181                                      LPVOID lpContext)
05182 {
05183     HKEY   hkResult;
05184     static const WCHAR searchSubKey[] = {
05185     'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
05186     'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
05187     'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
05188     'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
05189     static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
05190     static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
05191 
05192     DWORD  dwIndex;
05193     FILETIME filetime;
05194 
05195     char  *descriptionA = NULL;
05196     DWORD max_sizeOfDescriptionA = 0;
05197     WCHAR *descriptionW = NULL;
05198     DWORD max_sizeOfDescriptionW = 0;
05199 
05200     if (!lpEnumCallbackA && !lpEnumCallbackW)
05201     {
05202     return DPERR_INVALIDPARAMS;
05203     }
05204 
05205     /* Need to loop over the service providers in the registry */
05206     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
05207               0, KEY_READ, &hkResult) != ERROR_SUCCESS)
05208     {
05209     /* Hmmm. Does this mean that there are no service providers? */
05210     ERR(": no service provider key in the registry - check your Wine installation !!!\n");
05211     return DPERR_GENERIC;
05212     }
05213 
05214     /* Traverse all the service providers we have available */
05215     dwIndex = 0;
05216     while (1)
05217     {
05218     WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
05219     DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
05220     HKEY  hkServiceProvider;
05221     GUID  serviceProviderGUID;
05222     WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
05223     DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
05224     LONG  ret_value;
05225 
05226     ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
05227                   NULL, NULL, NULL, &filetime);
05228     if (ret_value == ERROR_NO_MORE_ITEMS)
05229         break;
05230     else if (ret_value != ERROR_SUCCESS)
05231     {
05232         ERR(": could not enumerate on service provider key.\n");
05233         return DPERR_EXCEPTION;
05234     }
05235     TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
05236 
05237     /* Open the key for this service provider */
05238     if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
05239     {
05240         ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
05241         continue;
05242     }
05243 
05244     /* Get the GUID from the registry */
05245     if (RegQueryValueExW(hkServiceProvider, guidKey,
05246                  NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
05247     {
05248         ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
05249         continue;
05250     }
05251     if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
05252     {
05253         ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
05254         continue;
05255     }
05256     CLSIDFromString(guidKeyContent, &serviceProviderGUID );
05257 
05258     /* The enumeration will return FALSE if we are not to continue.
05259      *
05260      * Note: on my windows box, major / minor version is 6 / 0 for all service providers
05261      *       and have no relations to any of the two dwReserved1 and dwReserved2 keys.
05262      *       I think that it simply means that they are in-line with DirectX 6.0
05263      */
05264     if (lpEnumCallbackA)
05265     {
05266         DWORD sizeOfDescription = 0;
05267 
05268         /* Note that this the the A case of this function, so use the A variant to get the description string */
05269         if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
05270                  NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
05271         {
05272         ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
05273         continue;
05274         }
05275         if (sizeOfDescription > max_sizeOfDescriptionA)
05276         {
05277         HeapFree(GetProcessHeap(), 0, descriptionA);
05278         max_sizeOfDescriptionA = sizeOfDescription;
05279         descriptionA = HeapAlloc(GetProcessHeap(), 0, max_sizeOfDescriptionA);
05280         }
05281         descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
05282         RegQueryValueExA(hkServiceProvider, "DescriptionA",
05283                  NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
05284 
05285         if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
05286         goto end;
05287     }
05288     else
05289     {
05290         DWORD sizeOfDescription = 0;
05291 
05292         if (RegQueryValueExW(hkServiceProvider, descW,
05293                  NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
05294         {
05295         ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
05296         continue;
05297         }
05298         if (sizeOfDescription > max_sizeOfDescriptionW)
05299         {
05300         HeapFree(GetProcessHeap(), 0, descriptionW);
05301         max_sizeOfDescriptionW = sizeOfDescription;
05302         descriptionW = HeapAlloc(GetProcessHeap(), 0, max_sizeOfDescriptionW);
05303         }
05304         descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
05305         RegQueryValueExW(hkServiceProvider, descW,
05306                  NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
05307 
05308         if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
05309         goto end;
05310     }
05311 
05312       dwIndex++;
05313   }
05314 
05315  end:
05316     HeapFree(GetProcessHeap(), 0, descriptionA);
05317     HeapFree(GetProcessHeap(), 0, descriptionW);
05318 
05319     return DP_OK;
05320 }
05321 
05322 /***************************************************************************
05323  *  DirectPlayEnumerate  [DPLAYX.9]
05324  *  DirectPlayEnumerateA [DPLAYX.2]
05325  */
05326 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
05327 {
05328     TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
05329 
05330     return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
05331 }
05332 
05333 /***************************************************************************
05334  *  DirectPlayEnumerateW [DPLAYX.3]
05335  */
05336 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
05337 {
05338     TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
05339 
05340     return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
05341 }
05342 
05343 typedef struct tagCreateEnum
05344 {
05345   LPVOID  lpConn;
05346   LPCGUID lpGuid;
05347 } CreateEnumData, *lpCreateEnumData;
05348 
05349 /* Find and copy the matching connection for the SP guid */
05350 static BOOL CALLBACK cbDPCreateEnumConnections(
05351     LPCGUID     lpguidSP,
05352     LPVOID      lpConnection,
05353     DWORD       dwConnectionSize,
05354     LPCDPNAME   lpName,
05355     DWORD       dwFlags,
05356     LPVOID      lpContext)
05357 {
05358   lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
05359 
05360   if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
05361   {
05362     TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
05363 
05364     lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
05365                                 dwConnectionSize );
05366     CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
05367 
05368     /* Found the record that we were looking for */
05369     return FALSE;
05370   }
05371 
05372   /* Haven't found what were looking for yet */
05373   return TRUE;
05374 }
05375 
05376 
05377 /***************************************************************************
05378  *  DirectPlayCreate [DPLAYX.1]
05379  *
05380  */
05381 HRESULT WINAPI DirectPlayCreate
05382 ( LPGUID lpGUID, LPDIRECTPLAY2 *lplpDP, IUnknown *pUnk)
05383 {
05384   HRESULT hr;
05385   LPDIRECTPLAY3A lpDP3A;
05386   CreateEnumData cbData;
05387 
05388   TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
05389 
05390   if( pUnk != NULL )
05391   {
05392     return CLASS_E_NOAGGREGATION;
05393   }
05394 
05395   /* Create an IDirectPlay object. We don't support that so we'll cheat and
05396      give them an IDirectPlay2A object and hope that doesn't cause problems */
05397   if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
05398   {
05399     return DPERR_UNAVAILABLE;
05400   }
05401 
05402   if( IsEqualGUID( &GUID_NULL, lpGUID ) )
05403   {
05404     /* The GUID_NULL means don't bind a service provider. Just return the
05405        interface as is */
05406     return DP_OK;
05407   }
05408 
05409   /* Bind the desired service provider since lpGUID is non NULL */
05410   TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
05411 
05412   /* We're going to use a DP3 interface */
05413   hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
05414                                     (LPVOID*)&lpDP3A );
05415   if( FAILED(hr) )
05416   {
05417     ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
05418     return hr;
05419   }
05420 
05421   cbData.lpConn = NULL;
05422   cbData.lpGuid = lpGUID;
05423 
05424   /* We were given a service provider, find info about it... */
05425   hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
05426                                      &cbData, DPCONNECTION_DIRECTPLAY );
05427   if( ( FAILED(hr) ) ||
05428       ( cbData.lpConn == NULL )
05429     )
05430   {
05431     ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
05432     IDirectPlayX_Release( lpDP3A );
05433     return DPERR_UNAVAILABLE;
05434   }
05435 
05436   /* Initialize the service provider */
05437   hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
05438   if( FAILED(hr) )
05439   {
05440     ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
05441     HeapFree( GetProcessHeap(), 0, cbData.lpConn );
05442     IDirectPlayX_Release( lpDP3A );
05443     return hr;
05444   }
05445 
05446   /* Release our version of the interface now that we're done with it */
05447   IDirectPlayX_Release( lpDP3A );
05448   HeapFree( GetProcessHeap(), 0, cbData.lpConn );
05449 
05450   return DP_OK;
05451 }

Generated on Sun May 27 2012 04:21:37 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.