1 /* Direct Play 2,3,4 Implementation
3 * Copyright 1998,1999,2000,2001 - Peter Hunnisett
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
39 #include "dplayx_global.h"
40 #include "name_server.h"
41 #include "dplayx_queue.h"
42 #include "wine/dplaysp.h"
43 #include "dplay_global.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
47 /* FIXME: Should this be externed? */
48 extern HRESULT DPL_CreateCompoundAddress
49 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
50 LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
53 /* Local function prototypes */
54 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
55 static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
56 LPDPNAME lpName, DWORD dwFlags,
57 HANDLE hEvent, BOOL bAnsi );
58 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
59 static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
60 LPVOID lpData, DWORD dwDataSize );
62 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, const DPID *lpid,
63 const DPNAME *lpName, DWORD dwFlags,
64 DPID idParent, BOOL bAnsi );
65 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
66 LPVOID lpData, DWORD dwDataSize );
67 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
68 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
69 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
74 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
75 static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
76 LPCDPNAME lpName, DWORD dwFlags,
78 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
80 /* Helper methods for player/group interfaces */
81 static HRESULT DP_IF_DeletePlayerFromGroup
82 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
83 DPID idPlayer, BOOL bAnsi );
84 static HRESULT DP_IF_CreatePlayer
85 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
86 LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
87 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
88 static HRESULT DP_IF_DestroyGroup
89 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
90 static HRESULT DP_IF_DestroyPlayer
91 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
92 static HRESULT DP_IF_EnumGroupPlayers
93 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
94 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
95 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
96 static HRESULT DP_IF_GetGroupData
97 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
98 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
99 static HRESULT DP_IF_GetGroupName
100 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
101 LPDWORD lpdwDataSize, BOOL bAnsi );
102 static HRESULT DP_IF_GetPlayerData
103 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
104 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
105 static HRESULT DP_IF_GetPlayerName
106 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
107 LPDWORD lpdwDataSize, BOOL bAnsi );
108 static HRESULT DP_IF_SetGroupName
109 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
110 DWORD dwFlags, BOOL bAnsi );
111 static HRESULT DP_IF_SetPlayerData
112 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
113 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
114 static HRESULT DP_IF_SetPlayerName
115 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
116 DWORD dwFlags, BOOL bAnsi );
117 static HRESULT DP_IF_AddGroupToGroup
118 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
119 static HRESULT DP_IF_CreateGroup
120 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
121 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
122 DWORD dwFlags, BOOL bAnsi );
123 static HRESULT DP_IF_CreateGroupInGroup
124 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
125 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
126 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
127 static HRESULT DP_IF_AddPlayerToGroup
128 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
129 DPID idPlayer, BOOL bAnsi );
130 static HRESULT DP_IF_DeleteGroupFromGroup
131 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
132 static HRESULT DP_SetSessionDesc
133 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
134 DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
135 static HRESULT DP_SecureOpen
136 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
137 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
139 static HRESULT DP_SendEx
140 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
141 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
142 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
143 static HRESULT DP_IF_Receive
144 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
145 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
146 static HRESULT DP_IF_GetMessageQueue
147 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
148 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
149 static HRESULT DP_SP_SendEx
150 ( IDirectPlay2Impl* This, DWORD dwFlags,
151 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
152 LPVOID lpContext, LPDWORD lpdwMsgID );
153 static HRESULT DP_IF_SetGroupData
154 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
155 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
156 static HRESULT DP_IF_GetPlayerCaps
157 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
159 static HRESULT DP_IF_CancelMessage
160 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
161 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
162 static HRESULT DP_IF_EnumGroupsInGroup
163 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
164 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
165 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
166 static HRESULT DP_IF_GetGroupParent
167 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
169 static HRESULT DP_IF_GetCaps
170 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
171 static HRESULT DP_IF_EnumSessions
172 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
173 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
174 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
175 static HRESULT DP_IF_InitializeConnection
176 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
177 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
178 LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
179 DWORD dwFlags, LPVOID lpContext );
180 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
181 LPDWORD lpdwBufSize );
185 static inline DPID DP_NextObjectId(void);
186 static DPID DP_GetRemoteNextObjectId(void);
188 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
189 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
190 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
193 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
194 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
195 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
202 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
203 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
204 we don't have to change much */
205 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
207 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
208 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
210 /* Strip out all dwFlags values for CREATEPLAYER msg */
211 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
213 static LONG kludgePlayerGroupId = 1000;
216 static inline IDirectPlayImpl *impl_from_IDirectPlay4A( IDirectPlay4A *iface )
218 return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4A_iface );
221 static inline IDirectPlayImpl *impl_from_IDirectPlay4( IDirectPlay4 *iface )
223 return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4_iface );
226 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
228 IDirectPlay2AImpl *This = lpDP;
230 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
231 if ( This->dp2 == NULL )
236 This->dp2->bConnectionOpen = FALSE;
238 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
239 This->dp2->dwEnumSessionLock = 0;
241 This->dp2->bHostInterface = FALSE;
243 DPQ_INIT(This->dp2->receiveMsgs);
244 DPQ_INIT(This->dp2->sendMsgs);
245 DPQ_INIT(This->dp2->repliesExpected);
247 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
249 /* FIXME: Memory leak */
253 /* Provide an initial session desc with nothing in it */
254 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
256 sizeof( *This->dp2->lpSessionDesc ) );
257 if( This->dp2->lpSessionDesc == NULL )
259 /* FIXME: Memory leak */
262 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
264 /* We are emulating a dp 6 implementation */
265 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
267 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
268 sizeof( *This->dp2->spData.lpCB ) );
269 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
270 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
272 /* This is the pointer to the service provider */
273 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
274 (LPVOID*)&This->dp2->spData.lpISP, This ) )
277 /* FIXME: Memory leak */
281 /* Setup lobby provider information */
282 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
283 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
284 sizeof( *This->dp2->dplspData.lpCB ) );
285 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
287 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
288 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
291 /* FIXME: Memory leak */
298 /* Definition of the global function in dplayx_queue.h. #
299 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
300 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
302 HeapFree( GetProcessHeap(), 0, elem );
305 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
307 IDirectPlay2AImpl *This = lpDP;
309 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
311 TerminateThread( This->dp2->hEnumSessionThread, 0 );
312 CloseHandle( This->dp2->hEnumSessionThread );
315 /* Finish with the SP - have it shutdown */
316 if( This->dp2->spData.lpCB->ShutdownEx )
318 DPSP_SHUTDOWNDATA data;
320 TRACE( "Calling SP ShutdownEx\n" );
322 data.lpISP = This->dp2->spData.lpISP;
324 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
326 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
328 TRACE( "Calling obsolete SP Shutdown\n" );
329 (*This->dp2->spData.lpCB->Shutdown)();
332 /* Unload the SP (if it exists) */
333 if( This->dp2->hServiceProvider != 0 )
335 FreeLibrary( This->dp2->hServiceProvider );
338 /* Unload the Lobby Provider (if it exists) */
339 if( This->dp2->hDPLobbyProvider != 0 )
341 FreeLibrary( This->dp2->hDPLobbyProvider );
344 /* FIXME: Need to delete receive and send msgs queue contents */
346 NS_DeleteSessionCache( This->dp2->lpNameServerData );
348 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
350 IDirectPlaySP_Release( This->dp2->spData.lpISP );
352 /* Delete the contents */
353 HeapFree( GetProcessHeap(), 0, This->dp2 );
358 static void dplay_destroy(IDirectPlayImpl *obj)
360 DP_DestroyDirectPlay2( obj );
361 obj->lock.DebugInfo->Spare[0] = 0;
362 DeleteCriticalSection( &obj->lock );
363 HeapFree( GetProcessHeap(), 0, obj );
366 static inline DPID DP_NextObjectId(void)
368 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
371 /* *lplpReply will be non NULL iff there is something to reply */
372 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
373 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
374 WORD wCommandId, WORD wVersion,
375 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
377 TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
378 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
383 /* Name server needs to handle this request */
384 case DPMSGCMD_ENUMSESSIONSREQUEST:
386 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
389 /* Name server needs to handle this request */
390 case DPMSGCMD_ENUMSESSIONSREPLY:
391 /* No reply expected */
392 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
393 This->dp2->spData.dwSPHeaderSize,
395 This->dp2->lpNameServerData );
398 case DPMSGCMD_REQUESTNEWPLAYERID:
400 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = lpcMessageBody;
402 LPDPMSG_NEWPLAYERIDREPLY lpReply;
404 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
406 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
408 FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
411 /* Setup the reply */
412 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
413 This->dp2->spData.dwSPHeaderSize );
415 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
416 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
417 lpReply->envelope.wVersion = DPMSGVER_DP6;
419 lpReply->dpidNewPlayerId = DP_NextObjectId();
421 TRACE( "Allocating new playerid 0x%08x from remote request\n",
422 lpReply->dpidNewPlayerId );
426 case DPMSGCMD_GETNAMETABLEREPLY:
427 case DPMSGCMD_NEWPLAYERIDREPLY:
429 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
432 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
436 case DPMSGCMD_JUSTENVELOPE:
437 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
438 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
439 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
442 case DPMSGCMD_FORWARDADDPLAYER:
447 TRACE( "Sending message to self to get my addr\n" );
448 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
452 case DPMSGCMD_FORWARDADDPLAYERNACK:
453 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
457 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
462 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
468 static HRESULT DP_IF_AddPlayerToGroup
469 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
470 DPID idPlayer, BOOL bAnsi )
473 lpPlayerList lpPList;
474 lpPlayerList lpNewPList;
476 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
477 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
479 if( This->dp2->connectionInitialized == NO_PROVIDER )
481 return DPERR_UNINITIALIZED;
485 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
487 return DPERR_INVALIDGROUP;
490 /* Find the player */
491 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
493 return DPERR_INVALIDPLAYER;
496 /* Create a player list (ie "shortcut" ) */
497 lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
498 if( lpNewPList == NULL )
500 return DPERR_CANTADDPLAYER;
503 /* Add the shortcut */
504 lpPList->lpPData->uRef++;
505 lpNewPList->lpPData = lpPList->lpPData;
507 /* Add the player to the list of players for this group */
508 DPQ_INSERT(lpGData->players,lpNewPList,players);
510 /* Let the SP know that we've added a player to the group */
511 if( This->dp2->spData.lpCB->AddPlayerToGroup )
513 DPSP_ADDPLAYERTOGROUPDATA data;
515 TRACE( "Calling SP AddPlayerToGroup\n" );
517 data.idPlayer = idPlayer;
518 data.idGroup = idGroup;
519 data.lpISP = This->dp2->spData.lpISP;
521 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
524 /* Inform all other peers of the addition of player to the group. If there are
525 * no peers keep this event quiet.
526 * Also, if this event was the result of another machine sending it to us,
527 * don't bother rebroadcasting it.
529 if( ( lpMsgHdr == NULL ) &&
530 This->dp2->lpSessionDesc &&
531 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
533 DPMSG_ADDPLAYERTOGROUP msg;
534 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
536 msg.dpIdGroup = idGroup;
537 msg.dpIdPlayer = idPlayer;
539 /* FIXME: Correct to just use send effectively? */
540 /* FIXME: Should size include data w/ message or just message "header" */
541 /* FIXME: Check return code */
542 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
548 static HRESULT WINAPI IDirectPlay4AImpl_QueryInterface( IDirectPlay4A *iface, REFIID riid,
551 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
552 return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
555 static HRESULT WINAPI IDirectPlay4Impl_QueryInterface( IDirectPlay4 *iface, REFIID riid,
558 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
560 if ( IsEqualGUID( &IID_IUnknown, riid ) )
562 TRACE( "(%p)->(IID_IUnknown %p)\n", This, ppv );
563 *ppv = &This->IDirectPlay4A_iface;
565 else if ( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
567 TRACE( "(%p)->(IID_IDirectPlay2A %p)\n", This, ppv );
568 *ppv = &This->IDirectPlay4A_iface;
570 else if ( IsEqualGUID( &IID_IDirectPlay2, riid ) )
572 TRACE( "(%p)->(IID_IDirectPlay2 %p)\n", This, ppv );
573 *ppv = &This->IDirectPlay4_iface;
575 else if ( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
577 TRACE( "(%p)->(IID_IDirectPlay3A %p)\n", This, ppv );
578 *ppv = &This->IDirectPlay4A_iface;
580 else if ( IsEqualGUID( &IID_IDirectPlay3, riid ) )
582 TRACE( "(%p)->(IID_IDirectPlay3 %p)\n", This, ppv );
583 *ppv = &This->IDirectPlay4_iface;
585 else if ( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
587 TRACE( "(%p)->(IID_IDirectPlay4A %p)\n", This, ppv );
588 *ppv = &This->IDirectPlay4A_iface;
590 else if ( IsEqualGUID( &IID_IDirectPlay4, riid ) )
592 TRACE( "(%p)->(IID_IDirectPlay4 %p)\n", This, ppv );
593 *ppv = &This->IDirectPlay4_iface;
597 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
599 return E_NOINTERFACE;
602 IUnknown_AddRef((IUnknown*)*ppv);
606 static ULONG WINAPI IDirectPlay4AImpl_AddRef(IDirectPlay4A *iface)
608 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
609 ULONG ref = InterlockedIncrement( &This->ref4A );
611 TRACE( "(%p) ref4A=%d\n", This, ref );
614 InterlockedIncrement( &This->numIfaces );
619 static ULONG WINAPI IDirectPlay4Impl_AddRef(IDirectPlay4 *iface)
621 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
622 ULONG ref = InterlockedIncrement( &This->ref4 );
624 TRACE( "(%p) ref4=%d\n", This, ref );
627 InterlockedIncrement( &This->numIfaces );
632 static ULONG WINAPI IDirectPlay4AImpl_Release(IDirectPlay4A *iface)
634 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
635 ULONG ref = InterlockedDecrement( &This->ref4A );
637 TRACE( "(%p) ref4A=%d\n", This, ref );
639 if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
640 dplay_destroy( This );
645 static ULONG WINAPI IDirectPlay4Impl_Release(IDirectPlay4 *iface)
647 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
648 ULONG ref = InterlockedDecrement( &This->ref4 );
650 TRACE( "(%p) ref4=%d\n", This, ref );
652 if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
653 dplay_destroy( This );
658 static HRESULT WINAPI IDirectPlay4AImpl_AddPlayerToGroup( IDirectPlay4A *iface, DPID idGroup,
661 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
662 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
665 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
666 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
668 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
669 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
672 static HRESULT WINAPI IDirectPlay4AImpl_Close( IDirectPlay4A *iface )
674 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
675 return IDirectPlayX_Close( &This->IDirectPlay4_iface);
678 static HRESULT WINAPI IDirectPlay4Impl_Close( IDirectPlay4 *iface )
680 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
683 TRACE( "(%p)", This );
685 /* FIXME: Need to find a new host I assume (how?) */
686 /* FIXME: Need to destroy all local groups */
687 /* FIXME: Need to migrate all remotely visible players to the new host */
689 /* Invoke the SP callback to inform of session close */
690 if( This->dp2->spData.lpCB->CloseEx )
694 TRACE( "Calling SP CloseEx\n" );
695 data.lpISP = This->dp2->spData.lpISP;
696 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
698 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
700 TRACE( "Calling SP Close (obsolete interface)\n" );
701 hr = (*This->dp2->spData.lpCB->Close)();
708 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
709 const DPNAME *lpName, DWORD dwFlags,
710 DPID idParent, BOOL bAnsi )
714 /* Allocate the new space and add to end of high level group list */
715 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
717 if( lpGData == NULL )
722 DPQ_INIT(lpGData->groups);
723 DPQ_INIT(lpGData->players);
725 /* Set the desired player ID - no sanity checking to see if it exists */
726 lpGData->dpid = *lpid;
728 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
730 /* FIXME: Should we check that the parent exists? */
731 lpGData->parent = idParent;
733 /* FIXME: Should we validate the dwFlags? */
734 lpGData->dwFlags = dwFlags;
736 TRACE( "Created group id 0x%08x\n", *lpid );
741 /* This method assumes that all links to it are already deleted */
743 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
747 TRACE( "(%p)->(0x%08x)\n", This, dpid );
749 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
751 if( lpGList == NULL )
753 ERR( "DPID 0x%08x not found\n", dpid );
757 if( --(lpGList->lpGData->uRef) )
759 FIXME( "Why is this not the last reference to group?\n" );
764 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
765 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
767 /* Remove and Delete Player List object */
768 HeapFree( GetProcessHeap(), 0, lpGList );
772 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
774 lpGroupList lpGroups;
776 TRACE( "(%p)->(0x%08x)\n", This, dpid );
778 if( dpid == DPID_SYSTEM_GROUP )
780 return This->dp2->lpSysGroup;
784 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
787 if( lpGroups == NULL )
792 return lpGroups->lpGData;
795 static HRESULT DP_IF_CreateGroup
796 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
797 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
798 DWORD dwFlags, BOOL bAnsi )
802 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
803 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
806 if( This->dp2->connectionInitialized == NO_PROVIDER )
808 return DPERR_UNINITIALIZED;
811 /* If the name is not specified, we must provide one */
812 if( DPID_UNKNOWN == *lpidGroup )
814 /* If we are the name server, we decide on the group ids. If not, we
815 * must ask for one before attempting a creation.
817 if( This->dp2->bHostInterface )
819 *lpidGroup = DP_NextObjectId();
823 *lpidGroup = DP_GetRemoteNextObjectId();
827 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
828 DPID_NOPARENT_GROUP, bAnsi );
830 if( lpGData == NULL )
832 return DPERR_CANTADDPLAYER; /* yes player not group */
835 if( DPID_SYSTEM_GROUP == *lpidGroup )
837 This->dp2->lpSysGroup = lpGData;
838 TRACE( "Inserting system group\n" );
842 /* Insert into the system group */
843 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
844 lpGroup->lpGData = lpGData;
846 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
849 /* Something is now referencing this data */
852 /* Set all the important stuff for the group */
853 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
855 /* FIXME: We should only create the system group if GetCaps returns
856 * DPCAPS_GROUPOPTIMIZED.
859 /* Let the SP know that we've created this group */
860 if( This->dp2->spData.lpCB->CreateGroup )
862 DPSP_CREATEGROUPDATA data;
863 DWORD dwCreateFlags = 0;
865 TRACE( "Calling SP CreateGroup\n" );
867 if( *lpidGroup == DPID_NOPARENT_GROUP )
868 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
870 if( lpMsgHdr == NULL )
871 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
873 if( dwFlags & DPGROUP_HIDDEN )
874 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
876 data.idGroup = *lpidGroup;
877 data.dwFlags = dwCreateFlags;
878 data.lpSPMessageHeader = lpMsgHdr;
879 data.lpISP = This->dp2->spData.lpISP;
881 (*This->dp2->spData.lpCB->CreateGroup)( &data );
884 /* Inform all other peers of the creation of a new group. If there are
885 * no peers keep this event quiet.
886 * Also if this message was sent to us, don't rebroadcast.
888 if( ( lpMsgHdr == NULL ) &&
889 This->dp2->lpSessionDesc &&
890 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
892 DPMSG_CREATEPLAYERORGROUP msg;
893 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
895 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
896 msg.dpId = *lpidGroup;
897 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
899 msg.dwDataSize = dwDataSize;
900 msg.dpnName = *lpGroupName;
901 msg.dpIdParent = DPID_NOPARENT_GROUP;
902 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
904 /* FIXME: Correct to just use send effectively? */
905 /* FIXME: Should size include data w/ message or just message "header" */
906 /* FIXME: Check return code */
907 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
908 0, 0, NULL, NULL, bAnsi );
914 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroup( IDirectPlay4A *iface, DPID *lpidGroup,
915 DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
917 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
919 *lpidGroup = DPID_UNKNOWN;
921 return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
925 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
926 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
927 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
929 *lpidGroup = DPID_UNKNOWN;
931 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
932 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
937 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
938 LPVOID lpData, DWORD dwDataSize )
940 /* Clear out the data with this player */
941 if( dwFlags & DPSET_LOCAL )
943 if ( lpGData->dwLocalDataSize != 0 )
945 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
946 lpGData->lpLocalData = NULL;
947 lpGData->dwLocalDataSize = 0;
952 if( lpGData->dwRemoteDataSize != 0 )
954 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
955 lpGData->lpRemoteData = NULL;
956 lpGData->dwRemoteDataSize = 0;
960 /* Reallocate for new data */
963 if( dwFlags & DPSET_LOCAL )
965 lpGData->lpLocalData = lpData;
966 lpGData->dwLocalDataSize = dwDataSize;
970 lpGData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
971 CopyMemory( lpGData->lpRemoteData, lpData, dwDataSize );
972 lpGData->dwRemoteDataSize = dwDataSize;
978 /* This function will just create the storage for the new player. */
980 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
981 LPDPNAME lpName, DWORD dwFlags,
982 HANDLE hEvent, BOOL bAnsi )
984 lpPlayerData lpPData;
986 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
988 /* Allocate the storage for the player and associate it with list element */
989 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
990 if( lpPData == NULL )
995 /* Set the desired player ID */
996 lpPData->dpid = *lpid;
998 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1000 lpPData->dwFlags = dwFlags;
1002 /* If we were given an event handle, duplicate it */
1005 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1006 GetCurrentProcess(), &lpPData->hEvent,
1007 0, FALSE, DUPLICATE_SAME_ACCESS )
1010 /* FIXME: Memory leak */
1011 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1015 /* Initialize the SP data section */
1016 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1018 TRACE( "Created player id 0x%08x\n", *lpid );
1020 if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1021 This->dp2->lpSessionDesc->dwCurrentPlayers++;
1026 /* Delete the contents of the DPNAME struct */
1028 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1030 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1031 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1034 /* This method assumes that all links to it are already deleted */
1036 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1038 lpPlayerList lpPList;
1040 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1042 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1044 if( lpPList == NULL )
1046 ERR( "DPID 0x%08x not found\n", dpid );
1050 /* Verify that this is the last reference to the data */
1051 if( --(lpPList->lpPData->uRef) )
1053 FIXME( "Why is this not the last reference to player?\n" );
1058 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1060 CloseHandle( lpPList->lpPData->hEvent );
1061 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1063 /* Delete Player List object */
1064 HeapFree( GetProcessHeap(), 0, lpPList );
1067 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1069 lpPlayerList lpPlayers;
1071 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1073 if(This->dp2->lpSysGroup == NULL)
1076 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1081 /* Basic area for Dst must already be allocated */
1082 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1086 ZeroMemory( lpDst, sizeof( *lpDst ) );
1087 lpDst->dwSize = sizeof( *lpDst );
1091 if( lpSrc->dwSize != sizeof( *lpSrc) )
1096 /* Delete any existing pointers */
1097 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1098 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1100 /* Copy as required */
1101 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1105 if( lpSrc->u1.lpszShortNameA )
1107 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1108 strlen(lpSrc->u1.lpszShortNameA)+1 );
1109 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1111 if( lpSrc->u2.lpszLongNameA )
1113 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1114 strlen(lpSrc->u2.lpszLongNameA)+1 );
1115 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1120 if( lpSrc->u1.lpszShortNameA )
1122 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1123 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1124 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1126 if( lpSrc->u2.lpszLongNameA )
1128 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1129 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1130 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1138 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1139 LPVOID lpData, DWORD dwDataSize )
1141 /* Clear out the data with this player */
1142 if( dwFlags & DPSET_LOCAL )
1144 if ( lpPData->dwLocalDataSize != 0 )
1146 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1147 lpPData->lpLocalData = NULL;
1148 lpPData->dwLocalDataSize = 0;
1153 if( lpPData->dwRemoteDataSize != 0 )
1155 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1156 lpPData->lpRemoteData = NULL;
1157 lpPData->dwRemoteDataSize = 0;
1161 /* Reallocate for new data */
1162 if( lpData != NULL )
1165 if( dwFlags & DPSET_LOCAL )
1167 lpPData->lpLocalData = lpData;
1168 lpPData->dwLocalDataSize = dwDataSize;
1172 lpPData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
1173 CopyMemory( lpPData->lpRemoteData, lpData, dwDataSize );
1174 lpPData->dwRemoteDataSize = dwDataSize;
1180 static HRESULT DP_IF_CreatePlayer
1181 ( IDirectPlay2Impl* This,
1182 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1184 LPDPNAME lpPlayerName,
1192 lpPlayerData lpPData;
1193 lpPlayerList lpPList;
1194 DWORD dwCreateFlags = 0;
1196 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1197 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1198 dwDataSize, dwFlags, bAnsi );
1199 if( This->dp2->connectionInitialized == NO_PROVIDER )
1201 return DPERR_UNINITIALIZED;
1206 dwFlags = DPPLAYER_SPECTATOR;
1209 if( lpidPlayer == NULL )
1211 return DPERR_INVALIDPARAMS;
1215 /* Determine the creation flags for the player. These will be passed
1216 * to the name server if requesting a player id and to the SP when
1217 * informing it of the player creation
1220 if( dwFlags & DPPLAYER_SERVERPLAYER )
1222 if( *lpidPlayer == DPID_SERVERPLAYER )
1224 /* Server player for the host interface */
1225 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1227 else if( *lpidPlayer == DPID_NAME_SERVER )
1229 /* Name server - master of everything */
1230 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1234 /* Server player for a non host interface */
1235 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1239 if( lpMsgHdr == NULL )
1240 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1243 /* Verify we know how to handle all the flags */
1244 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1245 ( dwFlags & DPPLAYER_SPECTATOR )
1249 /* Assume non fatal failure */
1250 ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1253 /* If the name is not specified, we must provide one */
1254 if( *lpidPlayer == DPID_UNKNOWN )
1256 /* If we are the session master, we dish out the group/player ids */
1257 if( This->dp2->bHostInterface )
1259 *lpidPlayer = DP_NextObjectId();
1263 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1267 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1274 /* FIXME: Would be nice to perhaps verify that we don't already have
1279 /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
1281 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1284 if( lpPData == NULL )
1286 return DPERR_CANTADDPLAYER;
1289 /* Create the list object and link it in */
1290 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1291 if( lpPList == NULL )
1293 FIXME( "Memory leak\n" );
1294 return DPERR_CANTADDPLAYER;
1298 lpPList->lpPData = lpPData;
1300 /* Add the player to the system group */
1301 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1303 /* Update the information and send it to all players in the session */
1304 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1306 /* Let the SP know that we've created this player */
1307 if( This->dp2->spData.lpCB->CreatePlayer )
1309 DPSP_CREATEPLAYERDATA data;
1311 data.idPlayer = *lpidPlayer;
1312 data.dwFlags = dwCreateFlags;
1313 data.lpSPMessageHeader = lpMsgHdr;
1314 data.lpISP = This->dp2->spData.lpISP;
1316 TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1317 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1319 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1324 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1328 /* Now let the SP know that this player is a member of the system group */
1329 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1331 DPSP_ADDPLAYERTOGROUPDATA data;
1333 data.idPlayer = *lpidPlayer;
1334 data.idGroup = DPID_SYSTEM_GROUP;
1335 data.lpISP = This->dp2->spData.lpISP;
1337 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1339 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1344 ERR( "Failed to add player to sys group with sp: %s\n",
1345 DPLAYX_HresultToString(hr) );
1350 if( This->dp2->bHostInterface == FALSE )
1352 /* Let the name server know about the creation of this player */
1353 /* FIXME: Is this only to be done for the creation of a server player or
1354 * is this used for regular players? If only for server players, move
1355 * this call to DP_SecureOpen(...);
1358 TRACE( "Sending message to self to get my addr\n" );
1359 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1362 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1365 /* Inform all other peers of the creation of a new player. If there are
1366 * no peers keep this quiet.
1367 * Also, if this was a remote event, no need to rebroadcast it.
1369 if( ( lpMsgHdr == NULL ) &&
1370 This->dp2->lpSessionDesc &&
1371 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1373 DPMSG_CREATEPLAYERORGROUP msg;
1374 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1376 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1377 msg.dpId = *lpidPlayer;
1378 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1379 msg.lpData = lpData;
1380 msg.dwDataSize = dwDataSize;
1381 msg.dpnName = *lpPlayerName;
1382 msg.dpIdParent = DPID_NOPARENT_GROUP;
1383 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1385 /* FIXME: Correct to just use send effectively? */
1386 /* FIXME: Should size include data w/ message or just message "header" */
1387 /* FIXME: Check return code */
1388 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1389 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1396 static HRESULT WINAPI IDirectPlay4AImpl_CreatePlayer( IDirectPlay4A *iface, DPID *lpidPlayer,
1397 DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1399 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1401 if( lpidPlayer == NULL )
1403 return DPERR_INVALIDPARAMS;
1406 if( dwFlags & DPPLAYER_SERVERPLAYER )
1408 *lpidPlayer = DPID_SERVERPLAYER;
1412 *lpidPlayer = DPID_UNKNOWN;
1415 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1416 lpData, dwDataSize, dwFlags, TRUE );
1419 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1420 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1421 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1423 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1425 if( lpidPlayer == NULL )
1427 return DPERR_INVALIDPARAMS;
1430 if( dwFlags & DPPLAYER_SERVERPLAYER )
1432 *lpidPlayer = DPID_SERVERPLAYER;
1436 *lpidPlayer = DPID_UNKNOWN;
1439 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1440 lpData, dwDataSize, dwFlags, FALSE );
1443 static DPID DP_GetRemoteNextObjectId(void)
1448 return DP_NextObjectId();
1451 static HRESULT DP_IF_DeletePlayerFromGroup
1452 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1453 DPID idPlayer, BOOL bAnsi )
1457 lpGroupData lpGData;
1458 lpPlayerList lpPList;
1460 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
1461 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1463 /* Find the group */
1464 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1466 return DPERR_INVALIDGROUP;
1469 /* Find the player */
1470 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1472 return DPERR_INVALIDPLAYER;
1475 /* Remove the player shortcut from the group */
1476 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1478 if( lpPList == NULL )
1480 return DPERR_INVALIDPLAYER;
1483 /* One less reference */
1484 lpPList->lpPData->uRef--;
1486 /* Delete the Player List element */
1487 HeapFree( GetProcessHeap(), 0, lpPList );
1489 /* Inform the SP if they care */
1490 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1492 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1494 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1496 data.idPlayer = idPlayer;
1497 data.idGroup = idGroup;
1498 data.lpISP = This->dp2->spData.lpISP;
1500 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1503 /* Need to send a DELETEPLAYERFROMGROUP message */
1504 FIXME( "Need to send a message\n" );
1509 static HRESULT WINAPI IDirectPlay4AImpl_DeletePlayerFromGroup( IDirectPlay4A *iface, DPID idGroup,
1512 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1513 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1516 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1517 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1519 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1520 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1523 typedef struct _DPRGOPContext
1525 IDirectPlay3Impl* This;
1528 } DPRGOPContext, *lpDPRGOPContext;
1530 static BOOL CALLBACK
1531 cbRemoveGroupOrPlayer(
1538 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1540 TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1541 dpId, dwPlayerType, lpCtxt->idGroup );
1543 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1545 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1550 ERR( "Unable to delete group 0x%08x from group 0x%08x\n",
1551 dpId, lpCtxt->idGroup );
1556 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1557 NULL, lpCtxt->idGroup,
1558 dpId, lpCtxt->bAnsi )
1562 ERR( "Unable to delete player 0x%08x from grp 0x%08x\n",
1563 dpId, lpCtxt->idGroup );
1567 return TRUE; /* Continue enumeration */
1570 static HRESULT DP_IF_DestroyGroup
1571 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1573 lpGroupData lpGData;
1574 DPRGOPContext context;
1576 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1577 This, lpMsgHdr, idGroup, bAnsi );
1579 /* Find the group */
1580 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1582 return DPERR_INVALIDPLAYER; /* yes player */
1585 context.This = (IDirectPlay3Impl*)This;
1586 context.bAnsi = bAnsi;
1587 context.idGroup = idGroup;
1589 /* Remove all players that this group has */
1590 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1591 cbRemoveGroupOrPlayer, &context, 0, bAnsi );
1593 /* Remove all links to groups that this group has since this is dp3 */
1594 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1595 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1597 /* Remove this group from the parent group - if it has one */
1598 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1599 ( lpGData->parent != DPID_SYSTEM_GROUP )
1602 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1606 /* Now delete this group data and list from the system group */
1607 DP_DeleteGroup( This, idGroup );
1609 /* Let the SP know that we've destroyed this group */
1610 if( This->dp2->spData.lpCB->DeleteGroup )
1612 DPSP_DELETEGROUPDATA data;
1614 FIXME( "data.dwFlags is incorrect\n" );
1616 data.idGroup = idGroup;
1618 data.lpISP = This->dp2->spData.lpISP;
1620 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1623 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1628 static HRESULT WINAPI IDirectPlay4AImpl_DestroyGroup( IDirectPlay4A *iface, DPID idGroup )
1630 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1631 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1634 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1635 ( LPDIRECTPLAY2 iface, DPID idGroup )
1637 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1638 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1641 typedef struct _DPFAGContext
1643 IDirectPlay2Impl* This;
1646 } DPFAGContext, *lpDPFAGContext;
1648 static HRESULT DP_IF_DestroyPlayer
1649 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1651 DPFAGContext cbContext;
1653 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1654 This, lpMsgHdr, idPlayer, bAnsi );
1656 if( This->dp2->connectionInitialized == NO_PROVIDER )
1658 return DPERR_UNINITIALIZED;
1661 if( DP_FindPlayer( This, idPlayer ) == NULL )
1663 return DPERR_INVALIDPLAYER;
1666 /* FIXME: If the player is remote, we must be the host to delete this */
1668 cbContext.This = This;
1669 cbContext.idPlayer = idPlayer;
1670 cbContext.bAnsi = bAnsi;
1672 /* Find each group and call DeletePlayerFromGroup if the player is a
1673 member of the group */
1674 IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, NULL, cbDeletePlayerFromAllGroups, &cbContext,
1677 /* Now delete player and player list from the sys group */
1678 DP_DeletePlayer( This, idPlayer );
1680 /* Let the SP know that we've destroyed this group */
1681 if( This->dp2->spData.lpCB->DeletePlayer )
1683 DPSP_DELETEPLAYERDATA data;
1685 FIXME( "data.dwFlags is incorrect\n" );
1687 data.idPlayer = idPlayer;
1689 data.lpISP = This->dp2->spData.lpISP;
1691 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1694 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1699 static BOOL CALLBACK
1700 cbDeletePlayerFromAllGroups(
1707 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1709 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1711 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
1714 /* Enumerate all groups in this group since this will normally only
1715 * be called for top level groups
1717 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
1719 cbDeletePlayerFromAllGroups,
1720 lpContext, DPENUMGROUPS_ALL,
1726 ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
1732 static HRESULT WINAPI IDirectPlay4AImpl_DestroyPlayer( IDirectPlay4A *iface, DPID idPlayer )
1734 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1735 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1738 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1739 ( LPDIRECTPLAY2 iface, DPID idPlayer )
1741 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1742 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1745 static HRESULT DP_IF_EnumGroupPlayers
1746 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1747 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1748 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1750 lpGroupData lpGData;
1751 lpPlayerList lpPList;
1753 FIXME("(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
1754 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1755 lpContext, dwFlags, bAnsi );
1757 if( This->dp2->connectionInitialized == NO_PROVIDER )
1759 return DPERR_UNINITIALIZED;
1762 /* Find the group */
1763 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1765 return DPERR_INVALIDGROUP;
1768 if( DPQ_IS_EMPTY( lpGData->players ) )
1773 lpPList = DPQ_FIRST( lpGData->players );
1775 /* Walk the players in this group */
1778 /* We do not enum the name server or app server as they are of no
1779 * consequence to the end user.
1781 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
1782 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
1786 /* FIXME: Need to add stuff for dwFlags checking */
1788 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1789 &lpPList->lpPData->name,
1790 lpPList->lpPData->dwFlags,
1794 /* User requested break */
1799 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
1804 lpPList = DPQ_NEXT( lpPList->players );
1810 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupPlayers( IDirectPlay4A *iface, DPID idGroup,
1811 GUID *lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1812 void *lpContext, DWORD dwFlags )
1814 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1815 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
1816 lpEnumPlayersCallback2, lpContext,
1820 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
1821 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
1822 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1823 LPVOID lpContext, DWORD dwFlags )
1825 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1826 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
1827 lpEnumPlayersCallback2, lpContext,
1831 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
1832 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroups( IDirectPlay4A *iface, GUID *instance,
1833 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1835 return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1839 static HRESULT WINAPI IDirectPlay4Impl_EnumGroups ( IDirectPlay4 *iface, GUID *instance,
1840 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1842 return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1846 static HRESULT WINAPI IDirectPlay4AImpl_EnumPlayers( IDirectPlay4A *iface, GUID *instance,
1847 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1849 return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1853 static HRESULT WINAPI IDirectPlay4Impl_EnumPlayers( IDirectPlay4 *iface, GUID *instance,
1854 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1856 return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1860 /* This function should call the registered callback function that the user
1861 passed into EnumSessions for each entry available.
1863 static void DP_InvokeEnumSessionCallbacks
1864 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
1869 LPDPSESSIONDESC2 lpSessionDesc;
1871 FIXME( ": not checking for conditions\n" );
1873 /* Not sure if this should be pruning but it's convenient */
1874 NS_PruneSessionCache( lpNSInfo );
1876 NS_ResetSessionEnumeration( lpNSInfo );
1878 /* Enumerate all sessions */
1879 /* FIXME: Need to indicate ANSI */
1880 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
1882 TRACE( "EnumSessionsCallback2 invoked\n" );
1883 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
1889 /* Invoke one last time to indicate that there is no more to come */
1890 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
1893 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
1895 EnumSessionAsyncCallbackData* data = lpContext;
1896 HANDLE hSuicideRequest = data->hSuicideRequest;
1897 DWORD dwTimeout = data->dwTimeout;
1899 TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
1905 /* Sleep up to dwTimeout waiting for request to terminate thread */
1906 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
1908 TRACE( "Thread terminating on terminate request\n" );
1912 /* Now resend the enum request */
1913 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
1914 data->dwEnumSessionFlags,
1919 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
1920 /* FIXME: Should we kill this thread? How to inform the main thread? */
1925 TRACE( "Thread terminating\n" );
1927 /* Clean up the thread data */
1928 CloseHandle( hSuicideRequest );
1929 HeapFree( GetProcessHeap(), 0, lpContext );
1931 /* FIXME: Need to have some notification to main app thread that this is
1932 * dead. It would serve two purposes. 1) allow sync on termination
1933 * so that we don't actually send something to ourselves when we
1934 * become name server (race condition) and 2) so that if we die
1935 * abnormally something else will be able to tell.
1941 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
1943 /* Does a thread exist? If so we were doing an async enum session */
1944 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
1946 TRACE( "Killing EnumSession thread %p\n",
1947 This->dp2->hEnumSessionThread );
1949 /* Request that the thread kill itself nicely */
1950 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
1951 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
1953 /* We no longer need to know about the thread */
1954 CloseHandle( This->dp2->hEnumSessionThread );
1956 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
1960 static HRESULT DP_IF_EnumSessions
1961 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
1962 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
1963 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1967 TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x,%u)\n",
1968 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
1970 if( This->dp2->connectionInitialized == NO_PROVIDER )
1972 return DPERR_UNINITIALIZED;
1975 /* Can't enumerate if the interface is already open */
1976 if( This->dp2->bConnectionOpen )
1978 return DPERR_GENERIC;
1982 /* The loading of a lobby provider _seems_ to require a backdoor loading
1983 * of the service provider to also associate with this DP object. This is
1984 * because the app doesn't seem to have to call EnumConnections and
1985 * InitializeConnection for the SP before calling this method. As such
1986 * we'll do their dirty work for them with a quick hack so as to always
1987 * load the TCP/IP service provider.
1989 * The correct solution would seem to involve creating a dialog box which
1990 * contains the possible SPs. These dialog boxes most likely follow SDK
1993 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
1995 LPVOID lpConnection;
1998 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2000 if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2002 ERR( "Can't build compound addr\n" );
2003 return DPERR_GENERIC;
2006 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2013 /* Free up the address buffer */
2014 HeapFree( GetProcessHeap(), 0, lpConnection );
2016 /* The SP is now initialized */
2017 This->dp2->bSPInitialized = TRUE;
2022 /* Use the service provider default? */
2023 if( dwTimeout == 0 )
2026 spCaps.dwSize = sizeof( spCaps );
2028 DP_IF_GetCaps( This, &spCaps, 0 );
2029 dwTimeout = spCaps.dwTimeout;
2031 /* The service provider doesn't provide one either! */
2032 if( dwTimeout == 0 )
2034 /* Provide the TCP/IP default */
2035 dwTimeout = DPMSG_WAIT_5_SECS;
2039 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2041 DP_KillEnumSessionThread( This );
2045 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2047 /* Enumerate everything presently in the local session cache */
2048 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2049 This->dp2->lpNameServerData, dwTimeout,
2052 if( This->dp2->dwEnumSessionLock != 0 )
2053 return DPERR_CONNECTING;
2055 /* See if we've already created a thread to service this interface */
2056 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2059 This->dp2->dwEnumSessionLock++;
2061 /* Send the first enum request inline since the user may cancel a dialog
2062 * if one is presented. Also, may also have a connecting return code.
2064 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2065 dwFlags, &This->dp2->spData );
2069 EnumSessionAsyncCallbackData* lpData
2070 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2071 /* FIXME: need to kill the thread on object deletion */
2072 lpData->lpSpData = &This->dp2->spData;
2074 lpData->requestGuid = lpsd->guidApplication;
2075 lpData->dwEnumSessionFlags = dwFlags;
2076 lpData->dwTimeout = dwTimeout;
2078 This->dp2->hKillEnumSessionThreadEvent =
2079 CreateEventW( NULL, TRUE, FALSE, NULL );
2081 if( !DuplicateHandle( GetCurrentProcess(),
2082 This->dp2->hKillEnumSessionThreadEvent,
2083 GetCurrentProcess(),
2084 &lpData->hSuicideRequest,
2085 0, FALSE, DUPLICATE_SAME_ACCESS )
2088 ERR( "Can't duplicate thread killing handle\n" );
2091 TRACE( ": creating EnumSessionsRequest thread\n" );
2093 This->dp2->hEnumSessionThread = CreateThread( NULL,
2095 DP_EnumSessionsSendAsyncRequestThread,
2100 This->dp2->dwEnumSessionLock--;
2105 /* Invalidate the session cache for the interface */
2106 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2108 /* Send the broadcast for session enumeration */
2109 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2111 &This->dp2->spData );
2114 SleepEx( dwTimeout, FALSE );
2116 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2117 This->dp2->lpNameServerData, dwTimeout,
2124 static HRESULT WINAPI IDirectPlay4AImpl_EnumSessions( IDirectPlay4A *iface, DPSESSIONDESC2 *lpsd,
2125 DWORD dwTimeout, LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, void *lpContext,
2128 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2129 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2130 lpContext, dwFlags, TRUE );
2133 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2134 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2135 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2136 LPVOID lpContext, DWORD dwFlags )
2138 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2139 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2140 lpContext, dwFlags, FALSE );
2143 static HRESULT DP_IF_GetPlayerCaps
2144 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2147 DPSP_GETCAPSDATA data;
2149 TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
2151 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2153 return DPERR_UNINITIALIZED;
2156 /* Query the service provider */
2157 data.idPlayer = idPlayer;
2158 data.dwFlags = dwFlags;
2159 data.lpCaps = lpDPCaps;
2160 data.lpISP = This->dp2->spData.lpISP;
2162 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2165 static HRESULT DP_IF_GetCaps
2166 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2168 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2171 static HRESULT WINAPI IDirectPlay4AImpl_GetCaps( IDirectPlay4A *iface, DPCAPS *lpDPCaps,
2174 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2175 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2178 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2179 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2181 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2182 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2185 static HRESULT DP_IF_GetGroupData
2186 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2187 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2189 lpGroupData lpGData;
2190 DWORD dwRequiredBufferSize;
2191 LPVOID lpCopyDataFrom;
2193 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2194 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2196 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2198 return DPERR_INVALIDGROUP;
2201 /* How much buffer is required? */
2202 if( dwFlags & DPSET_LOCAL )
2204 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2205 lpCopyDataFrom = lpGData->lpLocalData;
2209 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2210 lpCopyDataFrom = lpGData->lpRemoteData;
2213 /* Is the user requesting to know how big a buffer is required? */
2214 if( ( lpData == NULL ) ||
2215 ( *lpdwDataSize < dwRequiredBufferSize )
2218 *lpdwDataSize = dwRequiredBufferSize;
2219 return DPERR_BUFFERTOOSMALL;
2222 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2227 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupData( IDirectPlay4A *iface, DPID idGroup,
2228 void *lpData, DWORD *lpdwDataSize, DWORD dwFlags )
2230 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2231 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2235 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2236 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2237 LPDWORD lpdwDataSize, DWORD dwFlags )
2239 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2240 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2244 static HRESULT DP_IF_GetGroupName
2245 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2246 LPDWORD lpdwDataSize, BOOL bAnsi )
2248 lpGroupData lpGData;
2249 LPDPNAME lpName = lpData;
2250 DWORD dwRequiredDataSize;
2252 FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2253 This, idGroup, lpData, lpdwDataSize, bAnsi );
2255 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2257 return DPERR_INVALIDGROUP;
2260 dwRequiredDataSize = lpGData->name.dwSize;
2262 if( lpGData->name.u1.lpszShortNameA )
2264 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2267 if( lpGData->name.u2.lpszLongNameA )
2269 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2272 if( ( lpData == NULL ) ||
2273 ( *lpdwDataSize < dwRequiredDataSize )
2276 *lpdwDataSize = dwRequiredDataSize;
2277 return DPERR_BUFFERTOOSMALL;
2280 /* Copy the structure */
2281 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2283 if( lpGData->name.u1.lpszShortNameA )
2285 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2286 lpGData->name.u1.lpszShortNameA );
2290 lpName->u1.lpszShortNameA = NULL;
2293 if( lpGData->name.u1.lpszShortNameA )
2295 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2296 lpGData->name.u2.lpszLongNameA );
2300 lpName->u2.lpszLongNameA = NULL;
2306 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupName( IDirectPlay4A *iface, DPID idGroup,
2307 void *lpData, DWORD *lpdwDataSize )
2309 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2310 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2313 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2314 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2315 LPDWORD lpdwDataSize )
2317 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2318 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2321 static HRESULT WINAPI IDirectPlay4AImpl_GetMessageCount( IDirectPlay4A *iface, DPID player,
2324 return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2327 static HRESULT WINAPI IDirectPlay4Impl_GetMessageCount( IDirectPlay4 *iface, DPID player,
2330 return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2333 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAddress( IDirectPlay4A *iface, DPID player,
2334 void *data, DWORD *size )
2336 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2337 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2341 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAddress( IDirectPlay4 *iface, DPID player,
2342 void *data, DWORD *size )
2344 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2345 FIXME( "(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2349 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerCaps( IDirectPlay4A *iface, DPID idPlayer,
2350 DPCAPS *lpPlayerCaps, DWORD dwFlags )
2352 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2353 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2356 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2357 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2360 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2361 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2364 static HRESULT DP_IF_GetPlayerData
2365 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2366 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2368 lpPlayerList lpPList;
2369 DWORD dwRequiredBufferSize;
2370 LPVOID lpCopyDataFrom;
2372 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2373 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2375 if( This->dp2->connectionInitialized == NO_PROVIDER )
2377 return DPERR_UNINITIALIZED;
2380 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2382 return DPERR_INVALIDPLAYER;
2385 /* How much buffer is required? */
2386 if( dwFlags & DPSET_LOCAL )
2388 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2389 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2393 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2394 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2397 /* Is the user requesting to know how big a buffer is required? */
2398 if( ( lpData == NULL ) ||
2399 ( *lpdwDataSize < dwRequiredBufferSize )
2402 *lpdwDataSize = dwRequiredBufferSize;
2403 return DPERR_BUFFERTOOSMALL;
2406 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2411 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerData( IDirectPlay4A *iface, DPID idPlayer,
2412 void *lpData, DWORD *lpdwDataSize, DWORD dwFlags )
2414 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2415 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2419 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2420 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2421 LPDWORD lpdwDataSize, DWORD dwFlags )
2423 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2424 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2428 static HRESULT DP_IF_GetPlayerName
2429 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2430 LPDWORD lpdwDataSize, BOOL bAnsi )
2432 lpPlayerList lpPList;
2433 LPDPNAME lpName = lpData;
2434 DWORD dwRequiredDataSize;
2436 FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2437 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2439 if( This->dp2->connectionInitialized == NO_PROVIDER )
2441 return DPERR_UNINITIALIZED;
2444 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2446 return DPERR_INVALIDPLAYER;
2449 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2451 if( lpPList->lpPData->name.u1.lpszShortNameA )
2453 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2456 if( lpPList->lpPData->name.u2.lpszLongNameA )
2458 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2461 if( ( lpData == NULL ) ||
2462 ( *lpdwDataSize < dwRequiredDataSize )
2465 *lpdwDataSize = dwRequiredDataSize;
2466 return DPERR_BUFFERTOOSMALL;
2469 /* Copy the structure */
2470 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2472 if( lpPList->lpPData->name.u1.lpszShortNameA )
2474 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2475 lpPList->lpPData->name.u1.lpszShortNameA );
2479 lpName->u1.lpszShortNameA = NULL;
2482 if( lpPList->lpPData->name.u1.lpszShortNameA )
2484 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2485 lpPList->lpPData->name.u2.lpszLongNameA );
2489 lpName->u2.lpszLongNameA = NULL;
2495 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
2496 void *lpData, DWORD *lpdwDataSize )
2498 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2499 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2502 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2503 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2504 LPDWORD lpdwDataSize )
2506 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2507 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2510 static HRESULT DP_GetSessionDesc
2511 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2514 DWORD dwRequiredSize;
2516 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2518 if( This->dp2->connectionInitialized == NO_PROVIDER )
2520 return DPERR_UNINITIALIZED;
2523 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2525 return DPERR_INVALIDPARAMS;
2528 /* FIXME: Get from This->dp2->lpSessionDesc */
2529 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2531 if ( ( lpData == NULL ) ||
2532 ( *lpdwDataSize < dwRequiredSize )
2535 *lpdwDataSize = dwRequiredSize;
2536 return DPERR_BUFFERTOOSMALL;
2539 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2544 static HRESULT WINAPI IDirectPlay4AImpl_GetSessionDesc( IDirectPlay4A *iface, void *lpData,
2545 DWORD *lpdwDataSize )
2547 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2548 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2551 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2552 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2554 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2555 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2558 /* Intended only for COM compatibility. Always returns an error. */
2559 static HRESULT WINAPI IDirectPlay4AImpl_Initialize( IDirectPlay4A *iface, GUID *guid )
2561 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2562 TRACE("(%p)->(%p): no-op\n", This, guid );
2563 return DPERR_ALREADYINITIALIZED;
2566 static HRESULT WINAPI IDirectPlay4Impl_Initialize( IDirectPlay4 *iface, GUID *guid )
2568 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2569 TRACE( "(%p)->(%p): no-op\n", This, guid );
2570 return DPERR_ALREADYINITIALIZED;
2574 static HRESULT DP_SecureOpen
2575 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2576 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2581 FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2582 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2584 if( This->dp2->connectionInitialized == NO_PROVIDER )
2586 return DPERR_UNINITIALIZED;
2589 if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
2591 TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
2592 return DPERR_INVALIDPARAMS;
2595 if( This->dp2->bConnectionOpen )
2597 TRACE( ": rejecting already open connection.\n" );
2598 return DPERR_ALREADYINITIALIZED;
2601 /* If we're enumerating, kill the thread */
2602 DP_KillEnumSessionThread( This );
2604 if( dwFlags & DPOPEN_CREATE )
2606 /* Rightoo - this computer is the host and the local computer needs to be
2607 the name server so that others can join this session */
2608 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2610 This->dp2->bHostInterface = TRUE;
2612 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2615 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2620 /* Invoke the conditional callback for the service provider */
2621 if( This->dp2->spData.lpCB->Open )
2625 FIXME( "Not all data fields are correct. Need new parameter\n" );
2627 data.bCreate = (dwFlags & DPOPEN_CREATE ) != 0;
2628 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2629 : NS_GetNSAddr( This->dp2->lpNameServerData );
2630 data.lpISP = This->dp2->spData.lpISP;
2631 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) != 0;
2632 data.dwOpenFlags = dwFlags;
2633 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2635 hr = (*This->dp2->spData.lpCB->Open)(&data);
2638 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2644 /* Create the system group of which everything is a part of */
2645 DPID systemGroup = DPID_SYSTEM_GROUP;
2647 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2652 if( dwFlags & DPOPEN_JOIN )
2654 DPID dpidServerId = DPID_UNKNOWN;
2656 /* Create the server player for this interface. This way we can receive
2657 * messages for this session.
2659 /* FIXME: I suppose that we should be setting an event for a receive
2660 * type of thing. That way the messaging thread could know to wake
2661 * up. DPlay would then trigger the hEvent for the player the
2662 * message is directed to.
2664 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2666 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2669 else if( dwFlags & DPOPEN_CREATE )
2671 DPID dpidNameServerId = DPID_NAME_SERVER;
2673 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2674 0, DPPLAYER_SERVERPLAYER, bAnsi );
2679 ERR( "Couldn't create name server/system player: %s\n",
2680 DPLAYX_HresultToString(hr) );
2686 static HRESULT WINAPI IDirectPlay4AImpl_Open( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
2689 return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
2692 static HRESULT WINAPI IDirectPlay4Impl_Open( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
2695 return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
2698 static HRESULT DP_IF_Receive
2699 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2700 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2702 LPDPMSG lpMsg = NULL;
2704 FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
2705 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2707 if( This->dp2->connectionInitialized == NO_PROVIDER )
2709 return DPERR_UNINITIALIZED;
2714 dwFlags = DPRECEIVE_ALL;
2717 /* If the lpData is NULL, we must be peeking the message */
2718 if( ( lpData == NULL ) &&
2719 !( dwFlags & DPRECEIVE_PEEK )
2722 return DPERR_INVALIDPARAMS;
2725 if( dwFlags & DPRECEIVE_ALL )
2727 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2729 if( !( dwFlags & DPRECEIVE_PEEK ) )
2731 FIXME( "Remove from queue\n" );
2734 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2735 ( dwFlags & DPRECEIVE_FROMPLAYER )
2738 FIXME( "Find matching message 0x%08x\n", dwFlags );
2742 ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
2747 return DPERR_NOMESSAGES;
2750 /* Copy into the provided buffer */
2751 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
2756 static HRESULT WINAPI IDirectPlay4AImpl_Receive( IDirectPlay4A *iface, DPID *lpidFrom,
2757 DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
2759 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2760 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, TRUE );
2763 static HRESULT WINAPI DirectPlay2WImpl_Receive
2764 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
2765 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2767 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2768 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2769 lpData, lpdwDataSize, FALSE );
2772 static HRESULT WINAPI IDirectPlay4AImpl_Send( IDirectPlay4A *iface, DPID from, DPID to,
2773 DWORD flags, void *data, DWORD size )
2775 return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
2778 static HRESULT WINAPI IDirectPlay4Impl_Send( IDirectPlay4 *iface, DPID from, DPID to,
2779 DWORD flags, void *data, DWORD size )
2781 return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
2784 static HRESULT DP_IF_SetGroupData
2785 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2786 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
2788 lpGroupData lpGData;
2790 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
2791 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
2793 /* Parameter check */
2794 if( ( lpData == NULL ) &&
2798 return DPERR_INVALIDPARAMS;
2801 /* Find the pointer to the data for this player */
2802 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2804 return DPERR_INVALIDOBJECT;
2807 if( !(dwFlags & DPSET_LOCAL) )
2809 FIXME( "Was this group created by this interface?\n" );
2810 /* FIXME: If this is a remote update need to allow it but not
2815 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
2817 /* FIXME: Only send a message if this group is local to the session otherwise
2818 * it will have been rejected above
2820 if( !(dwFlags & DPSET_LOCAL) )
2822 FIXME( "Send msg?\n" );
2828 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupData( IDirectPlay4A *iface, DPID idGroup,
2829 void *lpData, DWORD dwDataSize, DWORD dwFlags )
2831 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2832 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
2835 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
2836 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2837 DWORD dwDataSize, DWORD dwFlags )
2839 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2840 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
2843 static HRESULT DP_IF_SetGroupName
2844 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
2845 DWORD dwFlags, BOOL bAnsi )
2847 lpGroupData lpGData;
2849 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
2850 lpGroupName, dwFlags, bAnsi );
2852 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2854 return DPERR_INVALIDGROUP;
2857 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
2859 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
2860 FIXME( "Message not sent and dwFlags ignored\n" );
2865 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupName( IDirectPlay4A *iface, DPID idGroup,
2866 DPNAME *lpGroupName, DWORD dwFlags )
2868 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2869 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
2872 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
2873 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
2876 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2877 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
2880 static HRESULT DP_IF_SetPlayerData
2881 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2882 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
2884 lpPlayerList lpPList;
2886 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
2887 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
2889 if( This->dp2->connectionInitialized == NO_PROVIDER )
2891 return DPERR_UNINITIALIZED;
2894 /* Parameter check */
2895 if( ( lpData == NULL ) &&
2899 return DPERR_INVALIDPARAMS;
2902 /* Find the pointer to the data for this player */
2903 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2905 return DPERR_INVALIDPLAYER;
2908 if( !(dwFlags & DPSET_LOCAL) )
2910 FIXME( "Was this group created by this interface?\n" );
2911 /* FIXME: If this is a remote update need to allow it but not
2916 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
2918 if( !(dwFlags & DPSET_LOCAL) )
2920 FIXME( "Send msg?\n" );
2926 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerData( IDirectPlay4A *iface, DPID idPlayer,
2927 void *lpData, DWORD dwDataSize, DWORD dwFlags )
2929 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2930 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
2934 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
2935 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2936 DWORD dwDataSize, DWORD dwFlags )
2938 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2939 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
2943 static HRESULT DP_IF_SetPlayerName
2944 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
2945 DWORD dwFlags, BOOL bAnsi )
2947 lpPlayerList lpPList;
2949 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
2950 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
2952 if( This->dp2->connectionInitialized == NO_PROVIDER )
2954 return DPERR_UNINITIALIZED;
2957 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2959 return DPERR_INVALIDGROUP;
2962 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
2964 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
2965 FIXME( "Message not sent and dwFlags ignored\n" );
2970 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
2971 DPNAME *lpPlayerName, DWORD dwFlags )
2973 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2974 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
2977 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
2978 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
2981 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2982 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
2985 static HRESULT DP_SetSessionDesc
2986 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
2987 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
2989 DWORD dwRequiredSize;
2990 LPDPSESSIONDESC2 lpTempSessDesc;
2992 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
2993 This, lpSessDesc, dwFlags, bInitial, bAnsi );
2995 if( This->dp2->connectionInitialized == NO_PROVIDER )
2997 return DPERR_UNINITIALIZED;
3002 return DPERR_INVALIDPARAMS;
3005 /* Only the host is allowed to update the session desc */
3006 if( !This->dp2->bHostInterface )
3008 return DPERR_ACCESSDENIED;
3011 /* FIXME: Copy into This->dp2->lpSessionDesc */
3012 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3013 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3015 if( lpTempSessDesc == NULL )
3017 return DPERR_OUTOFMEMORY;
3021 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3023 This->dp2->lpSessionDesc = lpTempSessDesc;
3025 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3028 /*Initializing session GUID*/
3029 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3031 /* If this is an external invocation of the interface, we should be
3032 * letting everyone know that things have changed. Otherwise this is
3033 * just an initialization and it doesn't need to be propagated.
3037 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3043 static HRESULT WINAPI IDirectPlay4AImpl_SetSessionDesc( IDirectPlay4A *iface,
3044 DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
3046 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3047 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3050 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3051 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3053 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3054 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3057 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3058 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3062 if( lpSessDesc == NULL )
3064 /* Hmmm..don't need any size? */
3065 ERR( "NULL lpSessDesc\n" );
3069 dwSize += sizeof( *lpSessDesc );
3073 if( lpSessDesc->u1.lpszSessionNameA )
3075 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3078 if( lpSessDesc->u2.lpszPasswordA )
3080 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3085 if( lpSessDesc->u1.lpszSessionName )
3087 dwSize += sizeof( WCHAR ) *
3088 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3091 if( lpSessDesc->u2.lpszPassword )
3093 dwSize += sizeof( WCHAR ) *
3094 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3101 /* Assumes that contiguous buffers are already allocated. */
3102 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3103 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3105 BYTE* lpStartOfFreeSpace;
3107 if( lpSessionDest == NULL )
3109 ERR( "NULL lpSessionDest\n" );
3113 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3115 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3119 if( lpSessionSrc->u1.lpszSessionNameA )
3121 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3122 lpSessionDest->u1.lpszSessionNameA );
3123 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3124 lpStartOfFreeSpace +=
3125 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3128 if( lpSessionSrc->u2.lpszPasswordA )
3130 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3131 lpSessionDest->u2.lpszPasswordA );
3132 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3137 if( lpSessionSrc->u1.lpszSessionName )
3139 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3140 lpSessionDest->u1.lpszSessionName );
3141 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3142 lpStartOfFreeSpace += sizeof(WCHAR) *
3143 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3146 if( lpSessionSrc->u2.lpszPassword )
3148 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3149 lpSessionDest->u2.lpszPassword );
3150 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3156 static HRESULT DP_IF_AddGroupToGroup
3157 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3159 lpGroupData lpGData;
3160 lpGroupList lpNewGList;
3162 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3164 if( This->dp2->connectionInitialized == NO_PROVIDER )
3166 return DPERR_UNINITIALIZED;
3169 if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3171 return DPERR_INVALIDGROUP;
3174 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3176 return DPERR_INVALIDGROUP;
3179 /* Create a player list (ie "shortcut" ) */
3180 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3181 if( lpNewGList == NULL )
3183 return DPERR_CANTADDPLAYER;
3186 /* Add the shortcut */
3188 lpNewGList->lpGData = lpGData;
3190 /* Add the player to the list of players for this group */
3191 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3193 /* Send a ADDGROUPTOGROUP message */
3194 FIXME( "Not sending message\n" );
3199 static HRESULT WINAPI IDirectPlay4AImpl_AddGroupToGroup( IDirectPlay4A *iface, DPID idParentGroup,
3202 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3203 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3206 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3207 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3209 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3210 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3213 static HRESULT DP_IF_CreateGroupInGroup
3214 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3215 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3216 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3218 lpGroupData lpGParentData;
3219 lpGroupList lpGList;
3220 lpGroupData lpGData;
3222 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3223 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3224 dwDataSize, dwFlags, bAnsi );
3226 if( This->dp2->connectionInitialized == NO_PROVIDER )
3228 return DPERR_UNINITIALIZED;
3231 /* Verify that the specified parent is valid */
3232 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3233 idParentGroup ) ) == NULL
3236 return DPERR_INVALIDGROUP;
3239 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3240 dwFlags, idParentGroup, bAnsi );
3242 if( lpGData == NULL )
3244 return DPERR_CANTADDPLAYER; /* yes player not group */
3247 /* Something else is referencing this data */
3250 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3252 /* The list has now been inserted into the interface group list. We now
3253 need to put a "shortcut" to this group in the parent group */
3254 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3255 if( lpGList == NULL )
3257 FIXME( "Memory leak\n" );
3258 return DPERR_CANTADDPLAYER; /* yes player not group */
3261 lpGList->lpGData = lpGData;
3263 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3265 /* Let the SP know that we've created this group */
3266 if( This->dp2->spData.lpCB->CreateGroup )
3268 DPSP_CREATEGROUPDATA data;
3270 TRACE( "Calling SP CreateGroup\n" );
3272 data.idGroup = *lpidGroup;
3273 data.dwFlags = dwFlags;
3274 data.lpSPMessageHeader = lpMsgHdr;
3275 data.lpISP = This->dp2->spData.lpISP;
3277 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3280 /* Inform all other peers of the creation of a new group. If there are
3281 * no peers keep this quiet.
3283 if( This->dp2->lpSessionDesc &&
3284 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3286 DPMSG_CREATEPLAYERORGROUP msg;
3288 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3289 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3290 msg.dpId = *lpidGroup;
3291 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3292 msg.lpData = lpData;
3293 msg.dwDataSize = dwDataSize;
3294 msg.dpnName = *lpGroupName;
3296 /* FIXME: Correct to just use send effectively? */
3297 /* FIXME: Should size include data w/ message or just message "header" */
3298 /* FIXME: Check return code */
3299 DP_SendEx( (IDirectPlay2Impl*)This,
3300 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3301 0, 0, NULL, NULL, bAnsi );
3307 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroupInGroup( IDirectPlay4A *iface,
3308 DPID idParentGroup, DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize,
3311 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3313 *lpidGroup = DPID_UNKNOWN;
3315 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
3316 dwDataSize, dwFlags, TRUE );
3319 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3320 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3321 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3324 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3326 *lpidGroup = DPID_UNKNOWN;
3328 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3329 lpGroupName, lpData, dwDataSize,
3333 static HRESULT DP_IF_DeleteGroupFromGroup
3334 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3336 lpGroupList lpGList;
3337 lpGroupData lpGParentData;
3339 TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3341 /* Is the parent group valid? */
3342 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3344 return DPERR_INVALIDGROUP;
3347 /* Remove the group from the parent group queue */
3348 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3350 if( lpGList == NULL )
3352 return DPERR_INVALIDGROUP;
3355 /* Decrement the ref count */
3356 lpGList->lpGData->uRef--;
3358 /* Free up the list item */
3359 HeapFree( GetProcessHeap(), 0, lpGList );
3361 /* Should send a DELETEGROUPFROMGROUP message */
3362 FIXME( "message not sent\n" );
3367 static HRESULT WINAPI IDirectPlay4AImpl_DeleteGroupFromGroup( IDirectPlay4A *iface,
3368 DPID idParentGroup, DPID idGroup )
3370 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3371 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3374 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3375 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3377 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3378 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3381 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3382 LPDWORD lpdwBufSize )
3384 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3387 dpCompoundAddress.dwDataSize = sizeof( GUID );
3388 dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3389 dpCompoundAddress.lpData = lpcSpGuid;
3391 *lplpAddrBuf = NULL;
3394 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3395 lpdwBufSize, TRUE );
3397 if( hr != DPERR_BUFFERTOOSMALL )
3399 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3403 /* Now allocate the buffer */
3404 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3407 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3408 lpdwBufSize, TRUE );
3411 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3418 static HRESULT WINAPI IDirectPlay4AImpl_EnumConnections( IDirectPlay4A *iface,
3419 const GUID *lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, void *lpContext,
3422 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3423 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3425 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3428 dwFlags = DPCONNECTION_DIRECTPLAY;
3431 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3432 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3435 return DPERR_INVALIDFLAGS;
3438 if( !lpEnumCallback )
3440 return DPERR_INVALIDPARAMS;
3443 /* Enumerate DirectPlay service providers */
3444 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3447 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3448 LPCSTR guidDataSubKey = "Guid";
3449 char subKeyName[51];
3450 DWORD dwIndex, sizeOfSubKeyName=50;
3453 /* Need to loop over the service providers in the registry */
3454 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3455 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3457 /* Hmmm. Does this mean that there are no service providers? */
3458 ERR(": no service providers?\n");
3463 /* Traverse all the service providers we have available */
3465 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3466 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3467 ++dwIndex, sizeOfSubKeyName=51 )
3470 HKEY hkServiceProvider;
3471 GUID serviceProviderGUID;
3472 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3473 char returnBuffer[51];
3478 LPVOID lpAddressBuffer = NULL;
3479 DWORD dwAddressBufferSize = 0;
3481 TRACE(" this time through: %s\n", subKeyName );
3483 /* Get a handle for this particular service provider */
3484 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3485 &hkServiceProvider ) != ERROR_SUCCESS )
3487 ERR(": what the heck is going on?\n" );
3491 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3492 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3493 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3495 ERR(": missing GUID registry data members\n" );
3496 RegCloseKey(hkServiceProvider);
3499 RegCloseKey(hkServiceProvider);
3501 /* FIXME: Check return types to ensure we're interpreting data right */
3502 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3503 CLSIDFromString( buff, &serviceProviderGUID );
3504 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3506 /* Fill in the DPNAME struct for the service provider */
3507 dpName.dwSize = sizeof( dpName );
3509 dpName.u1.lpszShortNameA = subKeyName;
3510 dpName.u2.lpszLongNameA = NULL;
3512 /* Create the compound address for the service provider.
3513 * NOTE: This is a gruesome architectural scar right now. DP
3514 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3515 * native dll just gets around this little bit by allocating an
3516 * 80 byte buffer which isn't even filled with a valid compound
3517 * address. Oh well. Creating a proper compound address is the
3518 * way to go anyways despite this method taking slightly more
3519 * heap space and realtime :) */
3521 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3523 &dwAddressBufferSize );
3526 ERR( "Can't build compound addr\n" );
3527 return DPERR_GENERIC;
3530 /* The enumeration will return FALSE if we are not to continue */
3531 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3532 &dpName, dwFlags, lpContext ) )
3539 /* Enumerate DirectPlayLobby service providers */
3540 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3543 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3544 LPCSTR guidDataSubKey = "Guid";
3545 char subKeyName[51];
3546 DWORD dwIndex, sizeOfSubKeyName=50;
3549 /* Need to loop over the service providers in the registry */
3550 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3551 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3553 /* Hmmm. Does this mean that there are no service providers? */
3554 ERR(": no service providers?\n");
3559 /* Traverse all the lobby providers we have available */
3561 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3562 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3563 ++dwIndex, sizeOfSubKeyName=51 )
3566 HKEY hkServiceProvider;
3567 GUID serviceProviderGUID;
3568 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3569 char returnBuffer[51];
3574 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3575 LPVOID lpAddressBuffer = NULL;
3576 DWORD dwAddressBufferSize = 0;
3578 TRACE(" this time through: %s\n", subKeyName );
3580 /* Get a handle for this particular service provider */
3581 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3582 &hkServiceProvider ) != ERROR_SUCCESS )
3584 ERR(": what the heck is going on?\n" );
3588 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3589 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3590 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3592 ERR(": missing GUID registry data members\n" );
3593 RegCloseKey(hkServiceProvider);
3596 RegCloseKey(hkServiceProvider);
3598 /* FIXME: Check return types to ensure we're interpreting data right */
3599 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3600 CLSIDFromString( buff, &serviceProviderGUID );
3601 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3603 /* Fill in the DPNAME struct for the service provider */
3604 dpName.dwSize = sizeof( dpName );
3606 dpName.u1.lpszShortNameA = subKeyName;
3607 dpName.u2.lpszLongNameA = NULL;
3609 /* Create the compound address for the service provider.
3610 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3611 nast stuff. This may be why the native dll just gets around this little bit by
3612 allocating an 80 byte buffer which isn't even a filled with a valid compound
3613 address. Oh well. Creating a proper compound address is the way to go anyways
3614 despite this method taking slightly more heap space and realtime :) */
3616 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3617 dpCompoundAddress.dwDataSize = sizeof( GUID );
3618 dpCompoundAddress.lpData = &serviceProviderGUID;
3620 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3621 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3623 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3627 /* Now allocate the buffer */
3628 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3630 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3631 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3633 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3634 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3638 /* The enumeration will return FALSE if we are not to continue */
3639 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3640 &dpName, dwFlags, lpContext ) )
3642 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3645 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3652 static HRESULT WINAPI IDirectPlay4Impl_EnumConnections( IDirectPlay4 *iface,
3653 const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
3655 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3656 FIXME( "(%p)->(%p,%p,%p,0x%08x): stub\n", This, application, enumcb, context, flags );
3660 static HRESULT DP_IF_EnumGroupsInGroup
3661 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3662 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3663 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3665 lpGroupList lpGList;
3666 lpGroupData lpGData;
3668 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
3669 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3670 lpContext, dwFlags, bAnsi );
3672 if( This->dp2->connectionInitialized == NO_PROVIDER )
3674 return DPERR_UNINITIALIZED;
3677 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3679 return DPERR_INVALIDGROUP;
3682 if( DPQ_IS_EMPTY( lpGData->groups ) )
3687 lpGList = DPQ_FIRST( lpGData->groups );
3691 /* FIXME: Should check dwFlags for match here */
3693 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3694 &lpGList->lpGData->name, dwFlags,
3697 return DP_OK; /* User requested break */
3700 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3705 lpGList = DPQ_NEXT( lpGList->groups );
3712 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupsInGroup( IDirectPlay4A *iface, DPID idGroup,
3713 GUID *lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, void *lpContext,
3716 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3717 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3718 lpEnumPlayersCallback2, lpContext, dwFlags,
3722 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3723 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3724 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3727 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3728 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3729 lpEnumPlayersCallback2, lpContext, dwFlags,
3733 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupConnectionSettings( IDirectPlay4A *iface,
3734 DWORD flags, DPID group, void *data, DWORD *size )
3736 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3737 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
3741 static HRESULT WINAPI IDirectPlay4Impl_GetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
3742 DPID group, void *data, DWORD *size )
3744 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3745 FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
3749 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
3750 REFGUID guidDataType,
3755 /* Looking for the GUID of the provider to load */
3756 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
3757 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
3760 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
3761 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
3763 if( dwDataSize != sizeof( GUID ) )
3765 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
3768 memcpy( lpContext, lpData, dwDataSize );
3770 /* There shouldn't be more than 1 GUID/compound address */
3774 /* Still waiting for what we want */
3779 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
3780 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
3783 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3784 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3785 LPCSTR guidDataSubKey = "Guid";
3786 LPCSTR majVerDataSubKey = "dwReserved1";
3787 LPCSTR minVerDataSubKey = "dwReserved2";
3788 LPCSTR pathSubKey = "Path";
3790 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
3792 /* FIXME: Cloned code with a quick hack. */
3793 for( i=0; i<2; i++ )
3796 LPCSTR searchSubKey;
3797 char subKeyName[51];
3798 DWORD dwIndex, sizeOfSubKeyName=50;
3801 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
3802 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
3805 /* Need to loop over the service providers in the registry */
3806 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3807 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3809 /* Hmmm. Does this mean that there are no service providers? */
3810 ERR(": no service providers?\n");
3814 /* Traverse all the service providers we have available */
3816 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3817 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3818 ++dwIndex, sizeOfSubKeyName=51 )
3821 HKEY hkServiceProvider;
3822 GUID serviceProviderGUID;
3823 DWORD returnType, sizeOfReturnBuffer = 255;
3824 char returnBuffer[256];
3828 TRACE(" this time through: %s\n", subKeyName );
3830 /* Get a handle for this particular service provider */
3831 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3832 &hkServiceProvider ) != ERROR_SUCCESS )
3834 ERR(": what the heck is going on?\n" );
3838 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3839 NULL, &returnType, (LPBYTE)returnBuffer,
3840 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3842 ERR(": missing GUID registry data members\n" );
3846 /* FIXME: Check return types to ensure we're interpreting data right */
3847 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3848 CLSIDFromString( buff, &serviceProviderGUID );
3849 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3851 /* Determine if this is the Service Provider that the user asked for */
3852 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
3857 if( i == 0 ) /* DP SP */
3859 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
3860 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
3861 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
3864 sizeOfReturnBuffer = 255;
3866 /* Get dwReserved1 */
3867 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
3868 NULL, &returnType, (LPBYTE)returnBuffer,
3869 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3871 ERR(": missing dwReserved1 registry data members\n") ;
3876 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
3878 sizeOfReturnBuffer = 255;
3880 /* Get dwReserved2 */
3881 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
3882 NULL, &returnType, (LPBYTE)returnBuffer,
3883 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3885 ERR(": missing dwReserved1 registry data members\n") ;
3890 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
3892 sizeOfReturnBuffer = 255;
3894 /* Get the path for this service provider */
3895 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
3896 NULL, NULL, (LPBYTE)returnBuffer,
3897 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
3899 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
3903 TRACE( "Loading %s\n", returnBuffer );
3904 return LoadLibraryA( returnBuffer );
3912 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
3915 LPDPSP_SPINIT SPInit;
3917 /* Initialize the service provider by calling SPInit */
3918 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
3920 if( SPInit == NULL )
3922 ERR( "Service provider doesn't provide SPInit interface?\n" );
3923 FreeLibrary( hServiceProvider );
3924 return DPERR_UNAVAILABLE;
3927 TRACE( "Calling SPInit (DP SP entry point)\n" );
3929 hr = (*SPInit)( &This->dp2->spData );
3933 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
3934 FreeLibrary( hServiceProvider );
3938 /* FIXME: Need to verify the sanity of the returned callback table
3939 * using IsBadCodePtr */
3940 This->dp2->bSPInitialized = TRUE;
3942 /* This interface is now initialized as a DP object */
3943 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
3945 /* Store the handle of the module so that we can unload it later */
3946 This->dp2->hServiceProvider = hServiceProvider;
3952 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
3955 LPSP_INIT DPLSPInit;
3957 /* Initialize the service provider by calling SPInit */
3958 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
3960 if( DPLSPInit == NULL )
3962 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
3963 FreeLibrary( hLobbyProvider );
3964 return DPERR_UNAVAILABLE;
3967 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
3969 hr = (*DPLSPInit)( &This->dp2->dplspData );
3973 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
3974 FreeLibrary( hLobbyProvider );
3978 /* FIXME: Need to verify the sanity of the returned callback table
3979 * using IsBadCodePtr */
3981 This->dp2->bDPLSPInitialized = TRUE;
3983 /* This interface is now initialized as a lobby object */
3984 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
3986 /* Store the handle of the module so that we can unload it later */
3987 This->dp2->hDPLobbyProvider = hLobbyProvider;
3992 static HRESULT DP_IF_InitializeConnection
3993 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
3995 HMODULE hServiceProvider;
3998 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
3999 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4001 TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4003 if ( lpConnection == NULL )
4005 return DPERR_INVALIDPARAMS;
4010 return DPERR_INVALIDFLAGS;
4013 if( This->dp2->connectionInitialized != NO_PROVIDER )
4015 return DPERR_ALREADYINITIALIZED;
4018 /* Find out what the requested SP is and how large this buffer is */
4019 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4020 dwAddrSize, &guidSP );
4024 ERR( "Invalid compound address?\n" );
4025 return DPERR_UNAVAILABLE;
4028 /* Load the service provider */
4029 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4031 if( hServiceProvider == 0 )
4033 ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4034 return DPERR_UNAVAILABLE;
4039 /* Fill in what we can of the Service Provider required information.
4040 * The rest was be done in DP_LoadSP
4042 This->dp2->spData.lpAddress = lpConnection;
4043 This->dp2->spData.dwAddressSize = dwAddrSize;
4044 This->dp2->spData.lpGuid = &guidSP;
4046 hr = DP_InitializeDPSP( This, hServiceProvider );
4050 This->dp2->dplspData.lpAddress = lpConnection;
4052 hr = DP_InitializeDPLSP( This, hServiceProvider );
4063 static HRESULT WINAPI IDirectPlay4AImpl_InitializeConnection( IDirectPlay4A *iface,
4064 void *lpConnection, DWORD dwFlags )
4066 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4068 /* This may not be externally invoked once either an SP or LP is initialized */
4069 if( This->dp2->connectionInitialized != NO_PROVIDER )
4071 return DPERR_ALREADYINITIALIZED;
4074 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4077 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4078 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4080 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4082 /* This may not be externally invoked once either an SP or LP is initialized */
4083 if( This->dp2->connectionInitialized != NO_PROVIDER )
4085 return DPERR_ALREADYINITIALIZED;
4088 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4091 static HRESULT WINAPI IDirectPlay4AImpl_SecureOpen( IDirectPlay4A *iface,
4092 const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
4093 const DPCREDENTIALS *lpCredentials )
4095 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4096 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4099 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4100 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4101 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4103 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4104 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4107 static HRESULT WINAPI IDirectPlay4AImpl_SendChatMessage( IDirectPlay4A *iface, DPID from,
4108 DPID to, DWORD flags, DPCHAT *chatmsg )
4110 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4111 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
4115 static HRESULT WINAPI IDirectPlay4Impl_SendChatMessage( IDirectPlay4 *iface, DPID from, DPID to,
4116 DWORD flags, DPCHAT *chatmsg )
4118 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4119 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
4123 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupConnectionSettings( IDirectPlay4A *iface,
4124 DWORD flags, DPID group, DPLCONNECTION *connection )
4126 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4127 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
4131 static HRESULT WINAPI IDirectPlay4Impl_SetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
4132 DPID group, DPLCONNECTION *connection )
4134 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4135 FIXME( "(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
4139 static HRESULT WINAPI IDirectPlay4AImpl_StartSession( IDirectPlay4A *iface, DWORD dwFlags,
4142 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4143 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4147 static HRESULT WINAPI IDirectPlay4Impl_StartSession( IDirectPlay4 *iface, DWORD flags, DPID group )
4149 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4150 FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, flags, group );
4154 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupFlags( IDirectPlay4A *iface, DPID idGroup,
4157 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4158 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4162 static HRESULT WINAPI IDirectPlay4Impl_GetGroupFlags( IDirectPlay4 *iface, DPID group,
4165 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4166 FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, flags );
4170 static HRESULT DP_IF_GetGroupParent
4171 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4174 lpGroupData lpGData;
4176 TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4178 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4180 return DPERR_INVALIDGROUP;
4183 *lpidGroup = lpGData->dpid;
4188 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupParent( IDirectPlay4A *iface, DPID idGroup,
4191 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4192 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4194 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4195 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4197 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4198 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4201 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAccount( IDirectPlay4A *iface, DPID player,
4202 DWORD flags, void *data, DWORD *size )
4204 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4205 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
4209 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAccount( IDirectPlay4 *iface, DPID player,
4210 DWORD flags, void *data, DWORD *size )
4212 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4213 FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
4217 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerFlags( IDirectPlay4A *iface, DPID idPlayer,
4220 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4221 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4225 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerFlags( IDirectPlay4 *iface, DPID player,
4228 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4229 FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, flags );
4233 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4234 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4236 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4237 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4241 static HRESULT WINAPI IDirectPlay4Impl_GetGroupOwner( IDirectPlay4 *iface, DPID group,
4244 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4245 FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, owner );
4249 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4250 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4252 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4253 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4257 static HRESULT WINAPI IDirectPlay4Impl_SetGroupOwner( IDirectPlay4 *iface, DPID group ,
4260 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4261 FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, owner );
4265 static HRESULT DP_SendEx
4266 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4267 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4268 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4270 BOOL bValidDestination = FALSE;
4272 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4274 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4275 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4277 if( This->dp2->connectionInitialized == NO_PROVIDER )
4279 return DPERR_UNINITIALIZED;
4282 /* FIXME: Add parameter checking */
4283 /* FIXME: First call to this needs to acquire a message id which will be
4284 * used for multiple sends
4287 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4289 /* Verify that the message is being sent from a valid local player. The
4290 * from player may be anonymous DPID_UNKNOWN
4292 if( idFrom != DPID_UNKNOWN )
4294 if( DP_FindPlayer( This, idFrom ) == NULL )
4296 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4297 return DPERR_INVALIDPLAYER;
4301 /* Verify that the message is being sent to a valid player, group or to
4302 * everyone. If it's valid, send it to those players.
4304 if( idTo == DPID_ALLPLAYERS )
4306 bValidDestination = TRUE;
4308 /* See if SP has the ability to multicast. If so, use it */
4309 if( This->dp2->spData.lpCB->SendToGroupEx )
4311 FIXME( "Use group sendex to group 0\n" );
4313 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4315 FIXME( "Use obsolete group send to group 0\n" );
4317 else /* No multicast, multiplicate */
4319 /* Send to all players we know about */
4320 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4324 if( ( !bValidDestination ) &&
4325 ( DP_FindPlayer( This, idTo ) != NULL )
4328 /* Have the service provider send this message */
4329 /* FIXME: Could optimize for local interface sends */
4330 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4331 dwTimeout, lpContext, lpdwMsgID );
4334 if( ( !bValidDestination ) &&
4335 ( DP_FindAnyGroup( This, idTo ) != NULL )
4338 bValidDestination = TRUE;
4340 /* See if SP has the ability to multicast. If so, use it */
4341 if( This->dp2->spData.lpCB->SendToGroupEx )
4343 FIXME( "Use group sendex\n" );
4345 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4347 FIXME( "Use obsolete group send to group\n" );
4349 else /* No multicast, multiplicate */
4351 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4359 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4361 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4362 if( dwWaitReturn != WAIT_OBJECT_0 )
4364 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4370 if( !bValidDestination )
4372 return DPERR_INVALIDPLAYER;
4376 /* FIXME: Should return what the send returned */
4382 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4383 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4384 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4385 LPVOID lpContext, LPDWORD lpdwMsgID )
4387 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4388 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4389 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4392 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4393 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4394 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4395 LPVOID lpContext, LPDWORD lpdwMsgID )
4397 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4398 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4399 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4402 static HRESULT DP_SP_SendEx
4403 ( IDirectPlay2Impl* This, DWORD dwFlags,
4404 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4405 LPVOID lpContext, LPDWORD lpdwMsgID )
4409 FIXME( ": stub\n" );
4411 /* FIXME: This queuing should only be for async messages */
4413 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4414 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4416 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4418 /* FIXME: Need to queue based on priority */
4419 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4424 static HRESULT DP_IF_GetMessageQueue
4425 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4426 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4430 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4431 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4433 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4434 /* FIXME: What about sends which are not immediate? */
4436 if( This->dp2->spData.lpCB->GetMessageQueue )
4438 DPSP_GETMESSAGEQUEUEDATA data;
4440 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4442 /* FIXME: None of this is documented :( */
4444 data.lpISP = This->dp2->spData.lpISP;
4445 data.dwFlags = dwFlags;
4446 data.idFrom = idFrom;
4448 data.lpdwNumMsgs = lpdwNumMsgs;
4449 data.lpdwNumBytes = lpdwNumBytes;
4451 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4455 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4461 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4462 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4463 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4465 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4466 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4467 lpdwNumBytes, TRUE );
4470 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4471 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4472 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4474 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4475 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4476 lpdwNumBytes, FALSE );
4479 static HRESULT DP_IF_CancelMessage
4480 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4481 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4485 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4486 This, dwMsgID, dwFlags, bAnsi );
4488 if( This->dp2->spData.lpCB->Cancel )
4490 DPSP_CANCELDATA data;
4492 TRACE( "Calling SP Cancel\n" );
4494 /* FIXME: Undocumented callback */
4496 data.lpISP = This->dp2->spData.lpISP;
4497 data.dwFlags = dwFlags;
4498 data.lprglpvSPMsgID = NULL;
4499 data.cSPMsgID = dwMsgID;
4500 data.dwMinPriority = dwMinPriority;
4501 data.dwMaxPriority = dwMaxPriority;
4503 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4507 FIXME( "SP doesn't implement Cancel\n" );
4513 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4514 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4516 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4520 return DPERR_INVALIDFLAGS;
4525 dwFlags |= DPCANCELSEND_ALL;
4528 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4531 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4532 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4534 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4538 return DPERR_INVALIDFLAGS;
4543 dwFlags |= DPCANCELSEND_ALL;
4546 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4549 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4550 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4553 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4557 return DPERR_INVALIDFLAGS;
4560 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4561 dwMaxPriority, TRUE );
4564 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4565 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4568 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4572 return DPERR_INVALIDFLAGS;
4575 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4576 dwMaxPriority, FALSE );
4579 /* Note: Hack so we can reuse the old functions without compiler warnings */
4580 # define XCAST(fun) (void*)
4581 static const IDirectPlay4Vtbl dp4_vt =
4583 IDirectPlay4Impl_QueryInterface,
4584 IDirectPlay4Impl_AddRef,
4585 IDirectPlay4Impl_Release,
4587 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
4588 IDirectPlay4Impl_Close,
4589 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
4590 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
4591 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
4592 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
4593 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
4594 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
4595 IDirectPlay4Impl_EnumGroups,
4596 IDirectPlay4Impl_EnumPlayers,
4597 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
4598 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
4599 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
4600 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
4601 IDirectPlay4Impl_GetMessageCount,
4602 IDirectPlay4Impl_GetPlayerAddress,
4603 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
4604 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
4605 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
4606 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
4607 IDirectPlay4Impl_Initialize,
4608 IDirectPlay4Impl_Open,
4609 XCAST(Receive)DirectPlay2WImpl_Receive,
4610 IDirectPlay4Impl_Send,
4611 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
4612 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
4613 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
4614 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
4615 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
4617 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
4618 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
4619 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
4620 IDirectPlay4Impl_EnumConnections,
4621 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
4622 IDirectPlay4Impl_GetGroupConnectionSettings,
4623 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
4624 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
4625 IDirectPlay4Impl_SendChatMessage,
4626 IDirectPlay4Impl_SetGroupConnectionSettings,
4627 IDirectPlay4Impl_StartSession,
4628 IDirectPlay4Impl_GetGroupFlags,
4629 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
4630 IDirectPlay4Impl_GetPlayerAccount,
4631 IDirectPlay4Impl_GetPlayerFlags,
4632 IDirectPlay4Impl_GetGroupOwner,
4633 IDirectPlay4Impl_SetGroupOwner,
4634 DirectPlay4WImpl_SendEx,
4635 DirectPlay4WImpl_GetMessageQueue,
4636 DirectPlay4WImpl_CancelMessage,
4637 DirectPlay4WImpl_CancelPriority
4641 static const IDirectPlay4Vtbl dp4A_vt =
4643 IDirectPlay4AImpl_QueryInterface,
4644 IDirectPlay4AImpl_AddRef,
4645 IDirectPlay4AImpl_Release,
4646 IDirectPlay4AImpl_AddPlayerToGroup,
4647 IDirectPlay4AImpl_Close,
4648 IDirectPlay4AImpl_CreateGroup,
4649 IDirectPlay4AImpl_CreatePlayer,
4650 IDirectPlay4AImpl_DeletePlayerFromGroup,
4651 IDirectPlay4AImpl_DestroyGroup,
4652 IDirectPlay4AImpl_DestroyPlayer,
4653 IDirectPlay4AImpl_EnumGroupPlayers,
4654 IDirectPlay4AImpl_EnumGroups,
4655 IDirectPlay4AImpl_EnumPlayers,
4656 IDirectPlay4AImpl_EnumSessions,
4657 IDirectPlay4AImpl_GetCaps,
4658 IDirectPlay4AImpl_GetGroupData,
4659 IDirectPlay4AImpl_GetGroupName,
4660 IDirectPlay4AImpl_GetMessageCount,
4661 IDirectPlay4AImpl_GetPlayerAddress,
4662 IDirectPlay4AImpl_GetPlayerCaps,
4663 IDirectPlay4AImpl_GetPlayerData,
4664 IDirectPlay4AImpl_GetPlayerName,
4665 IDirectPlay4AImpl_GetSessionDesc,
4666 IDirectPlay4AImpl_Initialize,
4667 IDirectPlay4AImpl_Open,
4668 IDirectPlay4AImpl_Receive,
4669 IDirectPlay4AImpl_Send,
4670 IDirectPlay4AImpl_SetGroupData,
4671 IDirectPlay4AImpl_SetGroupName,
4672 IDirectPlay4AImpl_SetPlayerData,
4673 IDirectPlay4AImpl_SetPlayerName,
4674 IDirectPlay4AImpl_SetSessionDesc,
4675 IDirectPlay4AImpl_AddGroupToGroup,
4676 IDirectPlay4AImpl_CreateGroupInGroup,
4677 IDirectPlay4AImpl_DeleteGroupFromGroup,
4678 IDirectPlay4AImpl_EnumConnections,
4679 IDirectPlay4AImpl_EnumGroupsInGroup,
4680 IDirectPlay4AImpl_GetGroupConnectionSettings,
4681 IDirectPlay4AImpl_InitializeConnection,
4682 IDirectPlay4AImpl_SecureOpen,
4683 IDirectPlay4AImpl_SendChatMessage,
4684 IDirectPlay4AImpl_SetGroupConnectionSettings,
4685 IDirectPlay4AImpl_StartSession,
4686 IDirectPlay4AImpl_GetGroupFlags,
4687 IDirectPlay4AImpl_GetGroupParent,
4688 IDirectPlay4AImpl_GetPlayerAccount,
4689 IDirectPlay4AImpl_GetPlayerFlags,
4691 DirectPlay4AImpl_GetGroupOwner,
4692 DirectPlay4AImpl_SetGroupOwner,
4693 DirectPlay4AImpl_SendEx,
4694 DirectPlay4AImpl_GetMessageQueue,
4695 DirectPlay4AImpl_CancelMessage,
4696 DirectPlay4AImpl_CancelPriority
4699 HRESULT dplay_create( REFIID riid, void **ppv )
4701 IDirectPlayImpl *obj;
4704 TRACE( "(%s, %p)\n", debugstr_guid( riid ), ppv );
4707 obj = HeapAlloc( GetProcessHeap(), 0, sizeof( *obj ) );
4709 return DPERR_OUTOFMEMORY;
4711 obj->IDirectPlay4A_iface.lpVtbl = &dp4A_vt;
4712 obj->IDirectPlay4_iface.lpVtbl = &dp4_vt;
4717 InitializeCriticalSection( &obj->lock );
4718 obj->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlayImpl.lock");
4720 if ( DP_CreateDirectPlay2( obj ) )
4721 hr = IDirectPlayX_QueryInterface( &obj->IDirectPlay4A_iface, riid, ppv );
4723 hr = DPERR_NOMEMORY;
4724 IDirectPlayX_Release( &obj->IDirectPlay4A_iface );
4730 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
4734 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
4736 if( lpPlayer == NULL )
4738 return DPERR_INVALIDPLAYER;
4741 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
4746 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
4750 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
4752 if( lpPlayer == NULL )
4754 return DPERR_INVALIDPLAYER;
4757 lpPlayer->lpPData->lpSPPlayerData = lpData;
4762 /***************************************************************************
4763 * DirectPlayEnumerateAW
4765 * The pointer to the structure lpContext will be filled with the
4766 * appropriate data for each service offered by the OS. These services are
4767 * not necessarily available on this particular machine but are defined
4768 * as simple service providers under the "Service Providers" registry key.
4769 * This structure is then passed to lpEnumCallback for each of the different
4772 * This API is useful only for applications written using DirectX3 or
4773 * worse. It is superseded by IDirectPlay3::EnumConnections which also
4774 * gives information on the actual connections.
4776 * defn of a service provider:
4777 * A dynamic-link library used by DirectPlay to communicate over a network.
4778 * The service provider contains all the network-specific code required
4779 * to send and receive messages. Online services and network operators can
4780 * supply service providers to use specialized hardware, protocols, communications
4781 * media, and network resources.
4784 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
4785 LPDPENUMDPCALLBACKW lpEnumCallbackW,
4789 static const WCHAR searchSubKey[] = {
4790 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
4791 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
4792 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
4793 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
4794 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
4795 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
4800 char *descriptionA = NULL;
4801 DWORD max_sizeOfDescriptionA = 0;
4802 WCHAR *descriptionW = NULL;
4803 DWORD max_sizeOfDescriptionW = 0;
4805 if (!lpEnumCallbackA && !lpEnumCallbackW)
4807 return DPERR_INVALIDPARAMS;
4810 /* Need to loop over the service providers in the registry */
4811 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
4812 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
4814 /* Hmmm. Does this mean that there are no service providers? */
4815 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
4816 return DPERR_GENERIC;
4819 /* Traverse all the service providers we have available */
4823 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
4824 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
4825 HKEY hkServiceProvider;
4826 GUID serviceProviderGUID;
4827 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
4828 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
4831 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4832 NULL, NULL, NULL, &filetime);
4833 if (ret_value == ERROR_NO_MORE_ITEMS)
4835 else if (ret_value != ERROR_SUCCESS)
4837 ERR(": could not enumerate on service provider key.\n");
4838 return DPERR_EXCEPTION;
4840 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
4842 /* Open the key for this service provider */
4843 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
4845 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
4849 /* Get the GUID from the registry */
4850 if (RegQueryValueExW(hkServiceProvider, guidKey,
4851 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
4853 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
4856 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
4858 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
4861 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
4863 /* The enumeration will return FALSE if we are not to continue.
4865 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
4866 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
4867 * I think that it simply means that they are in-line with DirectX 6.0
4869 if (lpEnumCallbackA)
4871 DWORD sizeOfDescription = 0;
4873 /* Note that this is the A case of this function, so use the A variant to get the description string */
4874 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
4875 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
4877 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
4880 if (sizeOfDescription > max_sizeOfDescriptionA)
4882 HeapFree(GetProcessHeap(), 0, descriptionA);
4883 max_sizeOfDescriptionA = sizeOfDescription;
4885 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
4886 RegQueryValueExA(hkServiceProvider, "DescriptionA",
4887 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
4889 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
4894 DWORD sizeOfDescription = 0;
4896 if (RegQueryValueExW(hkServiceProvider, descW,
4897 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
4899 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
4902 if (sizeOfDescription > max_sizeOfDescriptionW)
4904 HeapFree(GetProcessHeap(), 0, descriptionW);
4905 max_sizeOfDescriptionW = sizeOfDescription;
4907 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
4908 RegQueryValueExW(hkServiceProvider, descW,
4909 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
4911 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
4919 HeapFree(GetProcessHeap(), 0, descriptionA);
4920 HeapFree(GetProcessHeap(), 0, descriptionW);
4925 /***************************************************************************
4926 * DirectPlayEnumerate [DPLAYX.9]
4927 * DirectPlayEnumerateA [DPLAYX.2]
4929 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
4931 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
4933 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
4936 /***************************************************************************
4937 * DirectPlayEnumerateW [DPLAYX.3]
4939 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
4941 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
4943 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
4946 typedef struct tagCreateEnum
4950 } CreateEnumData, *lpCreateEnumData;
4952 /* Find and copy the matching connection for the SP guid */
4953 static BOOL CALLBACK cbDPCreateEnumConnections(
4955 LPVOID lpConnection,
4956 DWORD dwConnectionSize,
4961 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
4963 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
4965 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
4967 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4969 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
4971 /* Found the record that we were looking for */
4975 /* Haven't found what were looking for yet */
4980 /***************************************************************************
4981 * DirectPlayCreate [DPLAYX.1]
4984 HRESULT WINAPI DirectPlayCreate
4985 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
4988 LPDIRECTPLAY3A lpDP3A;
4989 CreateEnumData cbData;
4991 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
4995 return CLASS_E_NOAGGREGATION;
4998 if( (lplpDP == NULL) || (lpGUID == NULL) )
5000 return DPERR_INVALIDPARAMS;
5003 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5004 give them an IDirectPlay2A object and hope that doesn't cause problems */
5005 if ( dplay_create( &IID_IDirectPlay2A, (void**)lplpDP ) != DP_OK )
5006 return DPERR_UNAVAILABLE;
5008 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5010 /* The GUID_NULL means don't bind a service provider. Just return the
5015 /* Bind the desired service provider since lpGUID is non NULL */
5016 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5018 /* We're going to use a DP3 interface */
5019 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5023 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5027 cbData.lpConn = NULL;
5028 cbData.lpGuid = lpGUID;
5030 /* We were given a service provider, find info about it... */
5031 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5032 &cbData, DPCONNECTION_DIRECTPLAY );
5033 if( ( FAILED(hr) ) ||
5034 ( cbData.lpConn == NULL )
5037 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5038 IDirectPlayX_Release( lpDP3A );
5039 return DPERR_UNAVAILABLE;
5042 /* Initialize the service provider */
5043 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5046 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5047 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5048 IDirectPlayX_Release( lpDP3A );
5052 /* Release our version of the interface now that we're done with it */
5053 IDirectPlayX_Release( lpDP3A );
5054 HeapFree( GetProcessHeap(), 0, cbData.lpConn );