dplayx: Add a separate refcount for IDirectPlay2A.
[wine.git] / dlls / dplayx / dplay.c
blobed0bbe191cece3d23db3a60fb6a133dba420aee3
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
20 #define COBJMACROS
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <string.h>
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winerror.h"
31 #include "winbase.h"
32 #include "winnt.h"
33 #include "winreg.h"
34 #include "winnls.h"
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
38 #include "dplayx_global.h"
39 #include "name_server.h"
40 #include "dplayx_queue.h"
41 #include "wine/dplaysp.h"
42 #include "dplay_global.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
46 /* FIXME: Should this be externed? */
47 extern HRESULT DPL_CreateCompoundAddress
48 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
49 LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
52 /* Local function prototypes */
53 static lpPlayerList DP_FindPlayer( IDirectPlayImpl *This, DPID dpid );
54 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
55 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
56 LPVOID lpData, DWORD dwDataSize );
57 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
58 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
59 DWORD dwPlayerType,
60 LPCDPNAME lpName,
61 DWORD dwFlags,
62 LPVOID lpContext );
63 static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid );
65 /* Helper methods for player/group interfaces */
66 static HRESULT DP_SetSessionDesc( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpSessDesc,
67 DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
68 static HRESULT DP_SP_SendEx( IDirectPlayImpl *This, DWORD dwFlags, void *lpData, DWORD dwDataSize,
69 DWORD dwPriority, DWORD dwTimeout, void *lpContext, DWORD *lpdwMsgID );
70 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
71 LPDWORD lpdwBufSize );
73 static DPID DP_GetRemoteNextObjectId(void);
75 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
76 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
77 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
80 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
81 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
82 we don't have to change much */
83 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
85 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
86 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
88 /* Strip out all dwFlags values for CREATEPLAYER msg */
89 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
91 static LONG kludgePlayerGroupId = 1000;
94 static inline IDirectPlayImpl *impl_from_IDirectPlay2A( IDirectPlay2A *iface )
96 return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay2A_iface );
99 static inline IDirectPlayImpl *impl_from_IDirectPlay4A( IDirectPlay4A *iface )
101 return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4A_iface );
104 static inline IDirectPlayImpl *impl_from_IDirectPlay4( IDirectPlay4 *iface )
106 return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4_iface );
109 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
111 IDirectPlayImpl *This = lpDP;
113 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
114 if ( This->dp2 == NULL )
116 return FALSE;
119 This->dp2->bConnectionOpen = FALSE;
121 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
122 This->dp2->dwEnumSessionLock = 0;
124 This->dp2->bHostInterface = FALSE;
126 DPQ_INIT(This->dp2->receiveMsgs);
127 DPQ_INIT(This->dp2->sendMsgs);
128 DPQ_INIT(This->dp2->repliesExpected);
130 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
132 /* FIXME: Memory leak */
133 return FALSE;
136 /* Provide an initial session desc with nothing in it */
137 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
138 HEAP_ZERO_MEMORY,
139 sizeof( *This->dp2->lpSessionDesc ) );
140 if( This->dp2->lpSessionDesc == NULL )
142 /* FIXME: Memory leak */
143 return FALSE;
145 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
147 /* We are emulating a dp 6 implementation */
148 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
150 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
151 sizeof( *This->dp2->spData.lpCB ) );
152 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
153 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
155 /* This is the pointer to the service provider */
156 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
157 (LPVOID*)&This->dp2->spData.lpISP, This ) )
160 /* FIXME: Memory leak */
161 return FALSE;
164 /* Setup lobby provider information */
165 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
166 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
167 sizeof( *This->dp2->dplspData.lpCB ) );
168 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
170 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
171 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
174 /* FIXME: Memory leak */
175 return FALSE;
178 return TRUE;
181 /* Definition of the global function in dplayx_queue.h. #
182 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
183 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
185 HeapFree( GetProcessHeap(), 0, elem );
188 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
190 IDirectPlayImpl *This = lpDP;
192 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
194 TerminateThread( This->dp2->hEnumSessionThread, 0 );
195 CloseHandle( This->dp2->hEnumSessionThread );
198 /* Finish with the SP - have it shutdown */
199 if( This->dp2->spData.lpCB->ShutdownEx )
201 DPSP_SHUTDOWNDATA data;
203 TRACE( "Calling SP ShutdownEx\n" );
205 data.lpISP = This->dp2->spData.lpISP;
207 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
209 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
211 TRACE( "Calling obsolete SP Shutdown\n" );
212 (*This->dp2->spData.lpCB->Shutdown)();
215 /* Unload the SP (if it exists) */
216 if( This->dp2->hServiceProvider != 0 )
218 FreeLibrary( This->dp2->hServiceProvider );
221 /* Unload the Lobby Provider (if it exists) */
222 if( This->dp2->hDPLobbyProvider != 0 )
224 FreeLibrary( This->dp2->hDPLobbyProvider );
227 /* FIXME: Need to delete receive and send msgs queue contents */
229 NS_DeleteSessionCache( This->dp2->lpNameServerData );
231 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
233 IDirectPlaySP_Release( This->dp2->spData.lpISP );
235 /* Delete the contents */
236 HeapFree( GetProcessHeap(), 0, This->dp2 );
238 return TRUE;
241 static void dplay_destroy(IDirectPlayImpl *obj)
243 DP_DestroyDirectPlay2( obj );
244 obj->lock.DebugInfo->Spare[0] = 0;
245 DeleteCriticalSection( &obj->lock );
246 HeapFree( GetProcessHeap(), 0, obj );
249 static inline DPID DP_NextObjectId(void)
251 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
254 /* *lplpReply will be non NULL iff there is something to reply */
255 HRESULT DP_HandleMessage( IDirectPlayImpl *This, const void *lpcMessageBody,
256 DWORD dwMessageBodySize, const void *lpcMessageHeader, WORD wCommandId, WORD wVersion,
257 void **lplpReply, DWORD *lpdwMsgSize )
259 TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
260 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
261 wVersion );
263 switch( wCommandId )
265 /* Name server needs to handle this request */
266 case DPMSGCMD_ENUMSESSIONSREQUEST:
267 /* Reply expected */
268 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
269 break;
271 /* Name server needs to handle this request */
272 case DPMSGCMD_ENUMSESSIONSREPLY:
273 /* No reply expected */
274 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
275 This->dp2->spData.dwSPHeaderSize,
276 lpcMessageBody,
277 This->dp2->lpNameServerData );
278 break;
280 case DPMSGCMD_REQUESTNEWPLAYERID:
282 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = lpcMessageBody;
284 LPDPMSG_NEWPLAYERIDREPLY lpReply;
286 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
288 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
290 FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
291 lpcMsg->dwFlags );
293 /* Setup the reply */
294 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
295 This->dp2->spData.dwSPHeaderSize );
297 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
298 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
299 lpReply->envelope.wVersion = DPMSGVER_DP6;
301 lpReply->dpidNewPlayerId = DP_NextObjectId();
303 TRACE( "Allocating new playerid 0x%08x from remote request\n",
304 lpReply->dpidNewPlayerId );
305 break;
308 case DPMSGCMD_GETNAMETABLEREPLY:
309 case DPMSGCMD_NEWPLAYERIDREPLY:
310 #if 0
311 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
312 DebugBreak();
313 #endif
314 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
315 break;
317 #if 1
318 case DPMSGCMD_JUSTENVELOPE:
319 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
320 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
321 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
322 #endif
324 case DPMSGCMD_FORWARDADDPLAYER:
325 #if 0
326 DebugBreak();
327 #endif
328 #if 1
329 TRACE( "Sending message to self to get my addr\n" );
330 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
331 #endif
332 break;
334 case DPMSGCMD_FORWARDADDPLAYERNACK:
335 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
336 break;
338 default:
339 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
340 DebugBreak();
341 break;
344 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
346 return DP_OK;
350 static HRESULT WINAPI IDirectPlay2AImpl_QueryInterface( IDirectPlay2A *iface, REFIID riid,
351 void **ppv )
353 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
354 return IDirectPlayX_QueryInterface( &This->IDirectPlay4A_iface, riid, ppv );
357 static HRESULT WINAPI IDirectPlay4AImpl_QueryInterface( IDirectPlay4A *iface, REFIID riid,
358 void **ppv )
360 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
361 return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
364 static HRESULT WINAPI IDirectPlay4Impl_QueryInterface( IDirectPlay4 *iface, REFIID riid,
365 void **ppv )
367 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
369 if ( IsEqualGUID( &IID_IUnknown, riid ) )
371 TRACE( "(%p)->(IID_IUnknown %p)\n", This, ppv );
372 *ppv = &This->IDirectPlay4A_iface;
374 else if ( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
376 TRACE( "(%p)->(IID_IDirectPlay2A %p)\n", This, ppv );
377 *ppv = &This->IDirectPlay2A_iface;
379 else if ( IsEqualGUID( &IID_IDirectPlay2, riid ) )
381 TRACE( "(%p)->(IID_IDirectPlay2 %p)\n", This, ppv );
382 *ppv = &This->IDirectPlay4_iface;
384 else if ( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
386 TRACE( "(%p)->(IID_IDirectPlay3A %p)\n", This, ppv );
387 *ppv = &This->IDirectPlay4A_iface;
389 else if ( IsEqualGUID( &IID_IDirectPlay3, riid ) )
391 TRACE( "(%p)->(IID_IDirectPlay3 %p)\n", This, ppv );
392 *ppv = &This->IDirectPlay4_iface;
394 else if ( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
396 TRACE( "(%p)->(IID_IDirectPlay4A %p)\n", This, ppv );
397 *ppv = &This->IDirectPlay4A_iface;
399 else if ( IsEqualGUID( &IID_IDirectPlay4, riid ) )
401 TRACE( "(%p)->(IID_IDirectPlay4 %p)\n", This, ppv );
402 *ppv = &This->IDirectPlay4_iface;
404 else
406 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
407 *ppv = NULL;
408 return E_NOINTERFACE;
411 IUnknown_AddRef((IUnknown*)*ppv);
412 return S_OK;
415 static ULONG WINAPI IDirectPlay2AImpl_AddRef( IDirectPlay2A *iface )
417 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
418 ULONG ref = InterlockedIncrement( &This->ref2A );
420 TRACE( "(%p) ref2A=%d\n", This, ref );
422 if ( ref == 1 )
423 InterlockedIncrement( &This->numIfaces );
425 return ref;
428 static ULONG WINAPI IDirectPlay4AImpl_AddRef(IDirectPlay4A *iface)
430 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
431 ULONG ref = InterlockedIncrement( &This->ref4A );
433 TRACE( "(%p) ref4A=%d\n", This, ref );
435 if ( ref == 1 )
436 InterlockedIncrement( &This->numIfaces );
438 return ref;
441 static ULONG WINAPI IDirectPlay4Impl_AddRef(IDirectPlay4 *iface)
443 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
444 ULONG ref = InterlockedIncrement( &This->ref4 );
446 TRACE( "(%p) ref4=%d\n", This, ref );
448 if ( ref == 1 )
449 InterlockedIncrement( &This->numIfaces );
451 return ref;
454 static ULONG WINAPI IDirectPlay2AImpl_Release( IDirectPlay2A *iface )
456 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
457 ULONG ref = InterlockedDecrement( &This->ref2A );
459 TRACE( "(%p) ref2A=%d\n", This, ref );
461 if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
462 dplay_destroy( This );
464 return ref;
467 static ULONG WINAPI IDirectPlay4AImpl_Release(IDirectPlay4A *iface)
469 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
470 ULONG ref = InterlockedDecrement( &This->ref4A );
472 TRACE( "(%p) ref4A=%d\n", This, ref );
474 if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
475 dplay_destroy( This );
477 return ref;
480 static ULONG WINAPI IDirectPlay4Impl_Release(IDirectPlay4 *iface)
482 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
483 ULONG ref = InterlockedDecrement( &This->ref4 );
485 TRACE( "(%p) ref4=%d\n", This, ref );
487 if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
488 dplay_destroy( This );
490 return ref;
493 static HRESULT WINAPI IDirectPlay2AImpl_AddPlayerToGroup( IDirectPlay2A *iface, DPID group,
494 DPID player )
496 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
497 return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4A_iface, group, player );
500 static HRESULT WINAPI IDirectPlay4AImpl_AddPlayerToGroup( IDirectPlay4A *iface, DPID group,
501 DPID player )
503 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
504 return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
507 static HRESULT WINAPI IDirectPlay4Impl_AddPlayerToGroup( IDirectPlay4 *iface, DPID group,
508 DPID player )
510 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
511 lpGroupData gdata;
512 lpPlayerList plist;
513 lpPlayerList newplist;
515 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );
517 if ( This->dp2->connectionInitialized == NO_PROVIDER )
518 return DPERR_UNINITIALIZED;
520 /* Find the group */
521 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
522 return DPERR_INVALIDGROUP;
524 /* Find the player */
525 if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
526 return DPERR_INVALIDPLAYER;
528 /* Create a player list (ie "shortcut" ) */
529 newplist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *newplist ) );
530 if ( !newplist )
531 return DPERR_CANTADDPLAYER;
533 /* Add the shortcut */
534 plist->lpPData->uRef++;
535 newplist->lpPData = plist->lpPData;
537 /* Add the player to the list of players for this group */
538 DPQ_INSERT(gdata->players, newplist, players);
540 /* Let the SP know that we've added a player to the group */
541 if ( This->dp2->spData.lpCB->AddPlayerToGroup )
543 DPSP_ADDPLAYERTOGROUPDATA data;
545 TRACE( "Calling SP AddPlayerToGroup\n" );
547 data.idPlayer = player;
548 data.idGroup = group;
549 data.lpISP = This->dp2->spData.lpISP;
551 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
554 /* Inform all other peers of the addition of player to the group. If there are
555 * no peers keep this event quiet.
556 * Also, if this event was the result of another machine sending it to us,
557 * don't bother rebroadcasting it.
559 if ( This->dp2->lpSessionDesc &&
560 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
562 DPMSG_ADDPLAYERTOGROUP msg;
563 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
565 msg.dpIdGroup = group;
566 msg.dpIdPlayer = player;
568 /* FIXME: Correct to just use send effectively? */
569 /* FIXME: Should size include data w/ message or just message "header" */
570 /* FIXME: Check return code */
571 IDirectPlayX_SendEx( iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
572 0, 0, NULL, NULL );
575 return DP_OK;
578 static HRESULT WINAPI IDirectPlay2AImpl_Close( IDirectPlay2A *iface )
580 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
581 return IDirectPlayX_Close( &This->IDirectPlay4A_iface );
584 static HRESULT WINAPI IDirectPlay4AImpl_Close( IDirectPlay4A *iface )
586 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
587 return IDirectPlayX_Close( &This->IDirectPlay4_iface);
590 static HRESULT WINAPI IDirectPlay4Impl_Close( IDirectPlay4 *iface )
592 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
593 HRESULT hr = DP_OK;
595 TRACE( "(%p)\n", This );
597 /* FIXME: Need to find a new host I assume (how?) */
598 /* FIXME: Need to destroy all local groups */
599 /* FIXME: Need to migrate all remotely visible players to the new host */
601 /* Invoke the SP callback to inform of session close */
602 if( This->dp2->spData.lpCB->CloseEx )
604 DPSP_CLOSEDATA data;
606 TRACE( "Calling SP CloseEx\n" );
607 data.lpISP = This->dp2->spData.lpISP;
608 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
610 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
612 TRACE( "Calling SP Close (obsolete interface)\n" );
613 hr = (*This->dp2->spData.lpCB->Close)();
616 return hr;
619 static lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, const DPNAME *lpName,
620 DWORD dwFlags, DPID idParent, BOOL bAnsi )
622 lpGroupData lpGData;
624 /* Allocate the new space and add to end of high level group list */
625 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
627 if( lpGData == NULL )
629 return NULL;
632 DPQ_INIT(lpGData->groups);
633 DPQ_INIT(lpGData->players);
635 /* Set the desired player ID - no sanity checking to see if it exists */
636 lpGData->dpid = *lpid;
638 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
640 /* FIXME: Should we check that the parent exists? */
641 lpGData->parent = idParent;
643 /* FIXME: Should we validate the dwFlags? */
644 lpGData->dwFlags = dwFlags;
646 TRACE( "Created group id 0x%08x\n", *lpid );
648 return lpGData;
651 /* This method assumes that all links to it are already deleted */
652 static void DP_DeleteGroup( IDirectPlayImpl *This, DPID dpid )
654 lpGroupList lpGList;
656 TRACE( "(%p)->(0x%08x)\n", This, dpid );
658 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
660 if( lpGList == NULL )
662 ERR( "DPID 0x%08x not found\n", dpid );
663 return;
666 if( --(lpGList->lpGData->uRef) )
668 FIXME( "Why is this not the last reference to group?\n" );
669 DebugBreak();
672 /* Delete player */
673 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
674 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
676 /* Remove and Delete Player List object */
677 HeapFree( GetProcessHeap(), 0, lpGList );
681 static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid )
683 lpGroupList lpGroups;
685 TRACE( "(%p)->(0x%08x)\n", This, dpid );
687 if( dpid == DPID_SYSTEM_GROUP )
689 return This->dp2->lpSysGroup;
691 else
693 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
696 if( lpGroups == NULL )
698 return NULL;
701 return lpGroups->lpGData;
704 static HRESULT DP_IF_CreateGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidGroup,
705 DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
707 lpGroupData lpGData;
709 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
710 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
711 dwFlags, bAnsi );
713 if( This->dp2->connectionInitialized == NO_PROVIDER )
715 return DPERR_UNINITIALIZED;
718 /* If the name is not specified, we must provide one */
719 if( DPID_UNKNOWN == *lpidGroup )
721 /* If we are the name server, we decide on the group ids. If not, we
722 * must ask for one before attempting a creation.
724 if( This->dp2->bHostInterface )
726 *lpidGroup = DP_NextObjectId();
728 else
730 *lpidGroup = DP_GetRemoteNextObjectId();
734 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
735 DPID_NOPARENT_GROUP, bAnsi );
737 if( lpGData == NULL )
739 return DPERR_CANTADDPLAYER; /* yes player not group */
742 if( DPID_SYSTEM_GROUP == *lpidGroup )
744 This->dp2->lpSysGroup = lpGData;
745 TRACE( "Inserting system group\n" );
747 else
749 /* Insert into the system group */
750 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
751 lpGroup->lpGData = lpGData;
753 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
756 /* Something is now referencing this data */
757 lpGData->uRef++;
759 /* Set all the important stuff for the group */
760 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
762 /* FIXME: We should only create the system group if GetCaps returns
763 * DPCAPS_GROUPOPTIMIZED.
766 /* Let the SP know that we've created this group */
767 if( This->dp2->spData.lpCB->CreateGroup )
769 DPSP_CREATEGROUPDATA data;
770 DWORD dwCreateFlags = 0;
772 TRACE( "Calling SP CreateGroup\n" );
774 if( *lpidGroup == DPID_NOPARENT_GROUP )
775 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
777 if( lpMsgHdr == NULL )
778 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
780 if( dwFlags & DPGROUP_HIDDEN )
781 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
783 data.idGroup = *lpidGroup;
784 data.dwFlags = dwCreateFlags;
785 data.lpSPMessageHeader = lpMsgHdr;
786 data.lpISP = This->dp2->spData.lpISP;
788 (*This->dp2->spData.lpCB->CreateGroup)( &data );
791 /* Inform all other peers of the creation of a new group. If there are
792 * no peers keep this event quiet.
793 * Also if this message was sent to us, don't rebroadcast.
795 if( ( lpMsgHdr == NULL ) &&
796 This->dp2->lpSessionDesc &&
797 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
799 DPMSG_CREATEPLAYERORGROUP msg;
800 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
802 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
803 msg.dpId = *lpidGroup;
804 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
805 msg.lpData = lpData;
806 msg.dwDataSize = dwDataSize;
807 msg.dpnName = *lpGroupName;
808 msg.dpIdParent = DPID_NOPARENT_GROUP;
809 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
811 /* FIXME: Correct to just use send effectively? */
812 /* FIXME: Should size include data w/ message or just message "header" */
813 /* FIXME: Check return code */
814 IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
815 sizeof( msg ), 0, 0, NULL, NULL );
818 return DP_OK;
821 static HRESULT WINAPI IDirectPlay2AImpl_CreateGroup( IDirectPlay2A *iface, DPID *lpidGroup,
822 DPNAME *name, void *data, DWORD size, DWORD flags )
824 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
825 return IDirectPlayX_CreateGroup( &This->IDirectPlay4A_iface, lpidGroup, name, data, size,
826 flags );
829 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroup( IDirectPlay4A *iface, DPID *lpidGroup,
830 DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
832 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
834 *lpidGroup = DPID_UNKNOWN;
836 return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
837 TRUE );
840 static HRESULT WINAPI IDirectPlay4Impl_CreateGroup( IDirectPlay4 *iface, DPID *lpidGroup,
841 DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
843 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
845 *lpidGroup = DPID_UNKNOWN;
847 return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
848 FALSE );
852 static void
853 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
854 LPVOID lpData, DWORD dwDataSize )
856 /* Clear out the data with this player */
857 if( dwFlags & DPSET_LOCAL )
859 if ( lpGData->dwLocalDataSize != 0 )
861 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
862 lpGData->lpLocalData = NULL;
863 lpGData->dwLocalDataSize = 0;
866 else
868 if( lpGData->dwRemoteDataSize != 0 )
870 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
871 lpGData->lpRemoteData = NULL;
872 lpGData->dwRemoteDataSize = 0;
876 /* Reallocate for new data */
877 if( lpData != NULL )
879 if( dwFlags & DPSET_LOCAL )
881 lpGData->lpLocalData = lpData;
882 lpGData->dwLocalDataSize = dwDataSize;
884 else
886 lpGData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
887 CopyMemory( lpGData->lpRemoteData, lpData, dwDataSize );
888 lpGData->dwRemoteDataSize = dwDataSize;
894 /* This function will just create the storage for the new player. */
895 static lpPlayerData DP_CreatePlayer( IDirectPlayImpl *This, DPID *lpid, DPNAME *lpName,
896 DWORD dwFlags, HANDLE hEvent, BOOL bAnsi )
898 lpPlayerData lpPData;
900 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
902 /* Allocate the storage for the player and associate it with list element */
903 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
904 if( lpPData == NULL )
906 return NULL;
909 /* Set the desired player ID */
910 lpPData->dpid = *lpid;
912 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
914 lpPData->dwFlags = dwFlags;
916 /* If we were given an event handle, duplicate it */
917 if( hEvent != 0 )
919 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
920 GetCurrentProcess(), &lpPData->hEvent,
921 0, FALSE, DUPLICATE_SAME_ACCESS )
924 /* FIXME: Memory leak */
925 ERR( "Can't duplicate player msg handle %p\n", hEvent );
929 /* Initialize the SP data section */
930 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
932 TRACE( "Created player id 0x%08x\n", *lpid );
934 if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
935 This->dp2->lpSessionDesc->dwCurrentPlayers++;
937 return lpPData;
940 /* Delete the contents of the DPNAME struct */
941 static void
942 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
944 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
945 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
948 /* This method assumes that all links to it are already deleted */
949 static void DP_DeletePlayer( IDirectPlayImpl *This, DPID dpid )
951 lpPlayerList lpPList;
953 TRACE( "(%p)->(0x%08x)\n", This, dpid );
955 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
957 if( lpPList == NULL )
959 ERR( "DPID 0x%08x not found\n", dpid );
960 return;
963 /* Verify that this is the last reference to the data */
964 if( --(lpPList->lpPData->uRef) )
966 FIXME( "Why is this not the last reference to player?\n" );
967 DebugBreak();
970 /* Delete player */
971 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
973 CloseHandle( lpPList->lpPData->hEvent );
974 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
976 /* Delete Player List object */
977 HeapFree( GetProcessHeap(), 0, lpPList );
980 static lpPlayerList DP_FindPlayer( IDirectPlayImpl *This, DPID dpid )
982 lpPlayerList lpPlayers;
984 TRACE( "(%p)->(0x%08x)\n", This, dpid );
986 if(This->dp2->lpSysGroup == NULL)
987 return NULL;
989 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
991 return lpPlayers;
994 /* Basic area for Dst must already be allocated */
995 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
997 if( lpSrc == NULL )
999 ZeroMemory( lpDst, sizeof( *lpDst ) );
1000 lpDst->dwSize = sizeof( *lpDst );
1001 return TRUE;
1004 if( lpSrc->dwSize != sizeof( *lpSrc) )
1006 return FALSE;
1009 /* Delete any existing pointers */
1010 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1011 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1013 /* Copy as required */
1014 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1016 if( bAnsi )
1018 if( lpSrc->u1.lpszShortNameA )
1020 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1021 strlen(lpSrc->u1.lpszShortNameA)+1 );
1022 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1024 if( lpSrc->u2.lpszLongNameA )
1026 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1027 strlen(lpSrc->u2.lpszLongNameA)+1 );
1028 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1031 else
1033 if( lpSrc->u1.lpszShortNameA )
1035 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1036 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1037 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1039 if( lpSrc->u2.lpszLongNameA )
1041 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1042 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1043 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1047 return TRUE;
1050 static void
1051 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1052 LPVOID lpData, DWORD dwDataSize )
1054 /* Clear out the data with this player */
1055 if( dwFlags & DPSET_LOCAL )
1057 if ( lpPData->dwLocalDataSize != 0 )
1059 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1060 lpPData->lpLocalData = NULL;
1061 lpPData->dwLocalDataSize = 0;
1064 else
1066 if( lpPData->dwRemoteDataSize != 0 )
1068 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1069 lpPData->lpRemoteData = NULL;
1070 lpPData->dwRemoteDataSize = 0;
1074 /* Reallocate for new data */
1075 if( lpData != NULL )
1078 if( dwFlags & DPSET_LOCAL )
1080 lpPData->lpLocalData = lpData;
1081 lpPData->dwLocalDataSize = dwDataSize;
1083 else
1085 lpPData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
1086 CopyMemory( lpPData->lpRemoteData, lpData, dwDataSize );
1087 lpPData->dwRemoteDataSize = dwDataSize;
1093 /* Note: lpMsgHdr is NULL for local creation, non NULL for remote creation */
1094 static HRESULT DP_IF_CreatePlayer( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidPlayer,
1095 DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags,
1096 BOOL bAnsi )
1098 HRESULT hr = DP_OK;
1099 lpPlayerData lpPData;
1100 lpPlayerList lpPList;
1101 DWORD dwCreateFlags = 0;
1103 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1104 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1105 dwDataSize, dwFlags, bAnsi );
1106 if( This->dp2->connectionInitialized == NO_PROVIDER )
1108 return DPERR_UNINITIALIZED;
1111 if( dwFlags == 0 )
1113 dwFlags = DPPLAYER_SPECTATOR;
1116 if( lpidPlayer == NULL )
1118 return DPERR_INVALIDPARAMS;
1122 /* Determine the creation flags for the player. These will be passed
1123 * to the name server if requesting a player id and to the SP when
1124 * informing it of the player creation
1127 if( dwFlags & DPPLAYER_SERVERPLAYER )
1129 if( *lpidPlayer == DPID_SERVERPLAYER )
1131 /* Server player for the host interface */
1132 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1134 else if( *lpidPlayer == DPID_NAME_SERVER )
1136 /* Name server - master of everything */
1137 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1139 else
1141 /* Server player for a non host interface */
1142 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1146 if( lpMsgHdr == NULL )
1147 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1150 /* Verify we know how to handle all the flags */
1151 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1152 ( dwFlags & DPPLAYER_SPECTATOR )
1156 /* Assume non fatal failure */
1157 ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1160 /* If the name is not specified, we must provide one */
1161 if( *lpidPlayer == DPID_UNKNOWN )
1163 /* If we are the session master, we dish out the group/player ids */
1164 if( This->dp2->bHostInterface )
1166 *lpidPlayer = DP_NextObjectId();
1168 else
1170 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1172 if( FAILED(hr) )
1174 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1175 return hr;
1179 else
1181 /* FIXME: Would be nice to perhaps verify that we don't already have
1182 * this player.
1186 /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
1187 player total */
1188 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1189 hEvent, bAnsi );
1191 if( lpPData == NULL )
1193 return DPERR_CANTADDPLAYER;
1196 /* Create the list object and link it in */
1197 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1198 if( lpPList == NULL )
1200 FIXME( "Memory leak\n" );
1201 return DPERR_CANTADDPLAYER;
1204 lpPData->uRef = 1;
1205 lpPList->lpPData = lpPData;
1207 /* Add the player to the system group */
1208 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1210 /* Update the information and send it to all players in the session */
1211 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1213 /* Let the SP know that we've created this player */
1214 if( This->dp2->spData.lpCB->CreatePlayer )
1216 DPSP_CREATEPLAYERDATA data;
1218 data.idPlayer = *lpidPlayer;
1219 data.dwFlags = dwCreateFlags;
1220 data.lpSPMessageHeader = lpMsgHdr;
1221 data.lpISP = This->dp2->spData.lpISP;
1223 TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1224 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1226 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1229 if( FAILED(hr) )
1231 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1232 return hr;
1235 /* Now let the SP know that this player is a member of the system group */
1236 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1238 DPSP_ADDPLAYERTOGROUPDATA data;
1240 data.idPlayer = *lpidPlayer;
1241 data.idGroup = DPID_SYSTEM_GROUP;
1242 data.lpISP = This->dp2->spData.lpISP;
1244 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1246 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1249 if( FAILED(hr) )
1251 ERR( "Failed to add player to sys group with sp: %s\n",
1252 DPLAYX_HresultToString(hr) );
1253 return hr;
1256 #if 1
1257 if( This->dp2->bHostInterface == FALSE )
1259 /* Let the name server know about the creation of this player */
1260 /* FIXME: Is this only to be done for the creation of a server player or
1261 * is this used for regular players? If only for server players, move
1262 * this call to DP_SecureOpen(...);
1264 #if 0
1265 TRACE( "Sending message to self to get my addr\n" );
1266 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1267 #endif
1269 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1271 #else
1272 /* Inform all other peers of the creation of a new player. If there are
1273 * no peers keep this quiet.
1274 * Also, if this was a remote event, no need to rebroadcast it.
1276 if( ( lpMsgHdr == NULL ) &&
1277 This->dp2->lpSessionDesc &&
1278 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1280 DPMSG_CREATEPLAYERORGROUP msg;
1281 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1283 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1284 msg.dpId = *lpidPlayer;
1285 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1286 msg.lpData = lpData;
1287 msg.dwDataSize = dwDataSize;
1288 msg.dpnName = *lpPlayerName;
1289 msg.dpIdParent = DPID_NOPARENT_GROUP;
1290 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1292 /* FIXME: Correct to just use send effectively? */
1293 /* FIXME: Should size include data w/ message or just message "header" */
1294 /* FIXME: Check return code */
1295 hr = IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0,
1296 &msg, sizeof( msg ), 0, 0, NULL, NULL );
1298 #endif
1300 return hr;
1303 static HRESULT WINAPI IDirectPlay2AImpl_CreatePlayer( IDirectPlay2A *iface, DPID *lpidPlayer,
1304 DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
1306 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1307 return IDirectPlayX_CreatePlayer( &This->IDirectPlay4A_iface, lpidPlayer, name, event, data,
1308 size, flags );
1311 static HRESULT WINAPI IDirectPlay4AImpl_CreatePlayer( IDirectPlay4A *iface, DPID *lpidPlayer,
1312 DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1314 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1316 if( lpidPlayer == NULL )
1318 return DPERR_INVALIDPARAMS;
1321 if( dwFlags & DPPLAYER_SERVERPLAYER )
1323 *lpidPlayer = DPID_SERVERPLAYER;
1325 else
1327 *lpidPlayer = DPID_UNKNOWN;
1330 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1331 lpData, dwDataSize, dwFlags, TRUE );
1334 static HRESULT WINAPI IDirectPlay4Impl_CreatePlayer( IDirectPlay4 *iface, DPID *lpidPlayer,
1335 DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1337 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1339 if( lpidPlayer == NULL )
1341 return DPERR_INVALIDPARAMS;
1344 if( dwFlags & DPPLAYER_SERVERPLAYER )
1346 *lpidPlayer = DPID_SERVERPLAYER;
1348 else
1350 *lpidPlayer = DPID_UNKNOWN;
1353 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1354 lpData, dwDataSize, dwFlags, FALSE );
1357 static DPID DP_GetRemoteNextObjectId(void)
1359 FIXME( ":stub\n" );
1361 /* Hack solution */
1362 return DP_NextObjectId();
1365 static HRESULT WINAPI IDirectPlay2AImpl_DeletePlayerFromGroup( IDirectPlay2A *iface, DPID group,
1366 DPID player )
1368 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1369 return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4A_iface, group, player );
1372 static HRESULT WINAPI IDirectPlay4AImpl_DeletePlayerFromGroup( IDirectPlay4A *iface, DPID group,
1373 DPID player )
1375 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1376 return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1379 static HRESULT WINAPI IDirectPlay4Impl_DeletePlayerFromGroup( IDirectPlay4 *iface, DPID group,
1380 DPID player )
1382 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1383 HRESULT hr = DP_OK;
1385 lpGroupData gdata;
1386 lpPlayerList plist;
1388 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );
1390 /* Find the group */
1391 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
1392 return DPERR_INVALIDGROUP;
1394 /* Find the player */
1395 if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
1396 return DPERR_INVALIDPLAYER;
1398 /* Remove the player shortcut from the group */
1399 DPQ_REMOVE_ENTRY( gdata->players, players, lpPData->dpid, ==, player, plist );
1401 if ( !plist )
1402 return DPERR_INVALIDPLAYER;
1404 /* One less reference */
1405 plist->lpPData->uRef--;
1407 /* Delete the Player List element */
1408 HeapFree( GetProcessHeap(), 0, plist );
1410 /* Inform the SP if they care */
1411 if ( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1413 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1415 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1416 data.idPlayer = player;
1417 data.idGroup = group;
1418 data.lpISP = This->dp2->spData.lpISP;
1419 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1422 /* Need to send a DELETEPLAYERFROMGROUP message */
1423 FIXME( "Need to send a message\n" );
1425 return hr;
1428 typedef struct _DPRGOPContext
1430 IDirectPlayImpl *This;
1431 BOOL bAnsi;
1432 DPID idGroup;
1433 } DPRGOPContext, *lpDPRGOPContext;
1435 static BOOL CALLBACK
1436 cbRemoveGroupOrPlayer(
1437 DPID dpId,
1438 DWORD dwPlayerType,
1439 LPCDPNAME lpName,
1440 DWORD dwFlags,
1441 LPVOID lpContext )
1443 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1445 TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1446 dpId, dwPlayerType, lpCtxt->idGroup );
1448 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1450 if ( FAILED( IDirectPlayX_DeleteGroupFromGroup( &lpCtxt->This->IDirectPlay4_iface,
1451 lpCtxt->idGroup, dpId ) ) )
1452 ERR( "Unable to delete group 0x%08x from group 0x%08x\n", dpId, lpCtxt->idGroup );
1454 else if ( FAILED( IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface,
1455 lpCtxt->idGroup, dpId ) ) )
1456 ERR( "Unable to delete player 0x%08x from grp 0x%08x\n", dpId, lpCtxt->idGroup );
1458 return TRUE; /* Continue enumeration */
1461 static HRESULT DP_IF_DestroyGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID idGroup, BOOL bAnsi )
1463 lpGroupData lpGData;
1464 DPRGOPContext context;
1466 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1467 This, lpMsgHdr, idGroup, bAnsi );
1469 /* Find the group */
1470 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1472 return DPERR_INVALIDPLAYER; /* yes player */
1475 context.This = This;
1476 context.bAnsi = bAnsi;
1477 context.idGroup = idGroup;
1479 /* Remove all players that this group has */
1480 IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, idGroup, NULL, cbRemoveGroupOrPlayer,
1481 &context, 0 );
1483 /* Remove all links to groups that this group has since this is dp3 */
1484 IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, idGroup, NULL, cbRemoveGroupOrPlayer,
1485 (void*)&context, 0 );
1487 /* Remove this group from the parent group - if it has one */
1488 if( ( idGroup != DPID_SYSTEM_GROUP ) && ( lpGData->parent != DPID_SYSTEM_GROUP ) )
1489 IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, lpGData->parent, idGroup );
1491 /* Now delete this group data and list from the system group */
1492 DP_DeleteGroup( This, idGroup );
1494 /* Let the SP know that we've destroyed this group */
1495 if( This->dp2->spData.lpCB->DeleteGroup )
1497 DPSP_DELETEGROUPDATA data;
1499 FIXME( "data.dwFlags is incorrect\n" );
1501 data.idGroup = idGroup;
1502 data.dwFlags = 0;
1503 data.lpISP = This->dp2->spData.lpISP;
1505 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1508 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1510 return DP_OK;
1513 static HRESULT WINAPI IDirectPlay2AImpl_DestroyGroup( IDirectPlay2A *iface, DPID group )
1515 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1516 return IDirectPlayX_DestroyGroup( &This->IDirectPlay4A_iface, group );
1519 static HRESULT WINAPI IDirectPlay4AImpl_DestroyGroup( IDirectPlay4A *iface, DPID idGroup )
1521 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1522 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1525 static HRESULT WINAPI IDirectPlay4Impl_DestroyGroup( IDirectPlay4 *iface, DPID idGroup )
1527 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1528 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1531 typedef struct _DPFAGContext
1533 IDirectPlayImpl *This;
1534 DPID idPlayer;
1535 BOOL bAnsi;
1536 } DPFAGContext, *lpDPFAGContext;
1538 static HRESULT DP_IF_DestroyPlayer( IDirectPlayImpl *This, void *lpMsgHdr, DPID idPlayer,
1539 BOOL bAnsi )
1541 DPFAGContext cbContext;
1543 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1544 This, lpMsgHdr, idPlayer, bAnsi );
1546 if( This->dp2->connectionInitialized == NO_PROVIDER )
1548 return DPERR_UNINITIALIZED;
1551 if( DP_FindPlayer( This, idPlayer ) == NULL )
1553 return DPERR_INVALIDPLAYER;
1556 /* FIXME: If the player is remote, we must be the host to delete this */
1558 cbContext.This = This;
1559 cbContext.idPlayer = idPlayer;
1560 cbContext.bAnsi = bAnsi;
1562 /* Find each group and call DeletePlayerFromGroup if the player is a
1563 member of the group */
1564 IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, NULL, cbDeletePlayerFromAllGroups, &cbContext,
1565 DPENUMGROUPS_ALL );
1567 /* Now delete player and player list from the sys group */
1568 DP_DeletePlayer( This, idPlayer );
1570 /* Let the SP know that we've destroyed this group */
1571 if( This->dp2->spData.lpCB->DeletePlayer )
1573 DPSP_DELETEPLAYERDATA data;
1575 FIXME( "data.dwFlags is incorrect\n" );
1577 data.idPlayer = idPlayer;
1578 data.dwFlags = 0;
1579 data.lpISP = This->dp2->spData.lpISP;
1581 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1584 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1586 return DP_OK;
1589 static BOOL CALLBACK
1590 cbDeletePlayerFromAllGroups(
1591 DPID dpId,
1592 DWORD dwPlayerType,
1593 LPCDPNAME lpName,
1594 DWORD dwFlags,
1595 LPVOID lpContext )
1597 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1599 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1601 IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, lpCtxt->idPlayer );
1603 /* Enumerate all groups in this group since this will normally only
1604 * be called for top level groups
1606 IDirectPlayX_EnumGroupsInGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, NULL,
1607 cbDeletePlayerFromAllGroups, lpContext, DPENUMGROUPS_ALL);
1610 else
1612 ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
1615 return TRUE;
1618 static HRESULT WINAPI IDirectPlay2AImpl_DestroyPlayer( IDirectPlay2A *iface, DPID player )
1620 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1621 return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4A_iface, player );
1624 static HRESULT WINAPI IDirectPlay4AImpl_DestroyPlayer( IDirectPlay4A *iface, DPID idPlayer )
1626 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1627 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1630 static HRESULT WINAPI IDirectPlay4Impl_DestroyPlayer( IDirectPlay4 *iface, DPID idPlayer )
1632 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1633 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1636 static HRESULT WINAPI IDirectPlay2AImpl_EnumGroupPlayers( IDirectPlay2A *iface, DPID group,
1637 GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1639 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1640 return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4A_iface, group, instance,
1641 enumplayercb, context, flags );
1644 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupPlayers( IDirectPlay4A *iface, DPID group,
1645 GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1647 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1648 return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance, enumplayercb,
1649 context, flags );
1652 static HRESULT WINAPI IDirectPlay4Impl_EnumGroupPlayers( IDirectPlay4 *iface, DPID group,
1653 GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1655 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1656 lpGroupData gdata;
1657 lpPlayerList plist;
1659 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
1660 context, flags );
1662 if ( This->dp2->connectionInitialized == NO_PROVIDER )
1663 return DPERR_UNINITIALIZED;
1665 /* Find the group */
1666 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
1667 return DPERR_INVALIDGROUP;
1669 if ( DPQ_IS_EMPTY( gdata->players ) )
1670 return DP_OK;
1672 /* Walk the players in this group */
1673 for( plist = DPQ_FIRST( gdata->players ); ; plist = DPQ_NEXT( plist->players ) )
1675 /* We do not enum the name server or app server as they are of no
1676 * consequence to the end user.
1678 if ( ( plist->lpPData->dpid != DPID_NAME_SERVER ) &&
1679 ( plist->lpPData->dpid != DPID_SERVERPLAYER ) )
1681 /* FIXME: Need to add stuff for flags checking */
1682 if ( !enumplayercb( plist->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1683 &plist->lpPData->name, plist->lpPData->dwFlags, context ) )
1684 /* User requested break */
1685 return DP_OK;
1688 if ( DPQ_IS_ENDOFLIST( plist->players ) )
1689 break;
1691 return DP_OK;
1694 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
1695 static HRESULT WINAPI IDirectPlay2AImpl_EnumGroups( IDirectPlay2A *iface, GUID *instance,
1696 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1698 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1699 return IDirectPlayX_EnumGroups( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
1700 flags );
1703 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroups( IDirectPlay4A *iface, GUID *instance,
1704 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1706 return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1707 context, flags );
1710 static HRESULT WINAPI IDirectPlay4Impl_EnumGroups ( IDirectPlay4 *iface, GUID *instance,
1711 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1713 return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1714 context, flags );
1717 static HRESULT WINAPI IDirectPlay2AImpl_EnumPlayers( IDirectPlay2A *iface, GUID *instance,
1718 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1720 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1721 return IDirectPlayX_EnumPlayers( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
1722 flags );
1725 static HRESULT WINAPI IDirectPlay4AImpl_EnumPlayers( IDirectPlay4A *iface, GUID *instance,
1726 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1728 return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1729 context, flags );
1732 static HRESULT WINAPI IDirectPlay4Impl_EnumPlayers( IDirectPlay4 *iface, GUID *instance,
1733 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1735 return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1736 context, flags );
1739 /* This function should call the registered callback function that the user
1740 passed into EnumSessions for each entry available.
1742 static void DP_InvokeEnumSessionCallbacks
1743 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
1744 LPVOID lpNSInfo,
1745 DWORD dwTimeout,
1746 LPVOID lpContext )
1748 LPDPSESSIONDESC2 lpSessionDesc;
1750 FIXME( ": not checking for conditions\n" );
1752 /* Not sure if this should be pruning but it's convenient */
1753 NS_PruneSessionCache( lpNSInfo );
1755 NS_ResetSessionEnumeration( lpNSInfo );
1757 /* Enumerate all sessions */
1758 /* FIXME: Need to indicate ANSI */
1759 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
1761 TRACE( "EnumSessionsCallback2 invoked\n" );
1762 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
1764 return;
1768 /* Invoke one last time to indicate that there is no more to come */
1769 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
1772 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
1774 EnumSessionAsyncCallbackData* data = lpContext;
1775 HANDLE hSuicideRequest = data->hSuicideRequest;
1776 DWORD dwTimeout = data->dwTimeout;
1778 TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
1780 for( ;; )
1782 HRESULT hr;
1784 /* Sleep up to dwTimeout waiting for request to terminate thread */
1785 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
1787 TRACE( "Thread terminating on terminate request\n" );
1788 break;
1791 /* Now resend the enum request */
1792 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
1793 data->dwEnumSessionFlags,
1794 data->lpSpData );
1796 if( FAILED(hr) )
1798 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
1799 /* FIXME: Should we kill this thread? How to inform the main thread? */
1804 TRACE( "Thread terminating\n" );
1806 /* Clean up the thread data */
1807 CloseHandle( hSuicideRequest );
1808 HeapFree( GetProcessHeap(), 0, lpContext );
1810 /* FIXME: Need to have some notification to main app thread that this is
1811 * dead. It would serve two purposes. 1) allow sync on termination
1812 * so that we don't actually send something to ourselves when we
1813 * become name server (race condition) and 2) so that if we die
1814 * abnormally something else will be able to tell.
1817 return 1;
1820 static void DP_KillEnumSessionThread( IDirectPlayImpl *This )
1822 /* Does a thread exist? If so we were doing an async enum session */
1823 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
1825 TRACE( "Killing EnumSession thread %p\n",
1826 This->dp2->hEnumSessionThread );
1828 /* Request that the thread kill itself nicely */
1829 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
1830 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
1832 /* We no longer need to know about the thread */
1833 CloseHandle( This->dp2->hEnumSessionThread );
1835 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
1839 static HRESULT WINAPI IDirectPlay2AImpl_EnumSessions( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
1840 DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
1842 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1843 return IDirectPlayX_EnumSessions( &This->IDirectPlay4A_iface, sdesc, timeout, enumsessioncb,
1844 context, flags );
1847 static HRESULT WINAPI IDirectPlay4AImpl_EnumSessions( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
1848 DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
1850 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1851 return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
1852 context, flags );
1855 static HRESULT WINAPI IDirectPlay4Impl_EnumSessions( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
1856 DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
1858 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1859 void *connection;
1860 DWORD size;
1861 HRESULT hr = DP_OK;
1863 TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x)\n", This, sdesc, timeout, enumsessioncb,
1864 context, flags );
1866 if ( This->dp2->connectionInitialized == NO_PROVIDER )
1867 return DPERR_UNINITIALIZED;
1869 /* Can't enumerate if the interface is already open */
1870 if ( This->dp2->bConnectionOpen )
1871 return DPERR_GENERIC;
1873 /* The loading of a lobby provider _seems_ to require a backdoor loading
1874 * of the service provider to also associate with this DP object. This is
1875 * because the app doesn't seem to have to call EnumConnections and
1876 * InitializeConnection for the SP before calling this method. As such
1877 * we'll do their dirty work for them with a quick hack so as to always
1878 * load the TCP/IP service provider.
1880 * The correct solution would seem to involve creating a dialog box which
1881 * contains the possible SPs. These dialog boxes most likely follow SDK
1882 * examples.
1884 if ( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
1886 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
1888 if ( !DP_BuildSPCompoundAddr( (GUID*)&DPSPGUID_TCPIP, &connection, &size ) )
1890 ERR( "Can't build compound addr\n" );
1891 return DPERR_GENERIC;
1894 hr = IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, 0 );
1895 if ( FAILED(hr) )
1896 return hr;
1898 HeapFree( GetProcessHeap(), 0, connection );
1899 This->dp2->bSPInitialized = TRUE;
1903 /* Use the service provider default? */
1904 if ( !timeout )
1906 DPCAPS caps;
1907 caps.dwSize = sizeof( caps );
1909 IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, &caps, 0 );
1910 timeout = caps.dwTimeout;
1911 if ( !timeout )
1912 timeout = DPMSG_WAIT_5_SECS; /* Provide the TCP/IP default */
1915 if ( flags & DPENUMSESSIONS_STOPASYNC )
1917 DP_KillEnumSessionThread( This );
1918 return hr;
1921 if ( flags & DPENUMSESSIONS_ASYNC )
1923 /* Enumerate everything presently in the local session cache */
1924 DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
1925 context );
1927 if ( This->dp2->dwEnumSessionLock )
1928 return DPERR_CONNECTING;
1930 /* See if we've already created a thread to service this interface */
1931 if ( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
1933 DWORD tid;
1934 This->dp2->dwEnumSessionLock++;
1936 /* Send the first enum request inline since the user may cancel a dialog
1937 * if one is presented. Also, may also have a connecting return code.
1939 hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags,
1940 &This->dp2->spData );
1942 if ( SUCCEEDED(hr) )
1944 EnumSessionAsyncCallbackData* data = HeapAlloc( GetProcessHeap(),
1945 HEAP_ZERO_MEMORY, sizeof( *data ) );
1946 /* FIXME: need to kill the thread on object deletion */
1947 data->lpSpData = &This->dp2->spData;
1948 data->requestGuid = sdesc->guidApplication;
1949 data->dwEnumSessionFlags = flags;
1950 data->dwTimeout = timeout;
1952 This->dp2->hKillEnumSessionThreadEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1953 if ( !DuplicateHandle( GetCurrentProcess(), This->dp2->hKillEnumSessionThreadEvent,
1954 GetCurrentProcess(), &data->hSuicideRequest, 0, FALSE,
1955 DUPLICATE_SAME_ACCESS ) )
1956 ERR( "Can't duplicate thread killing handle\n" );
1958 TRACE( ": creating EnumSessionsRequest thread\n" );
1959 This->dp2->hEnumSessionThread = CreateThread( NULL, 0,
1960 DP_EnumSessionsSendAsyncRequestThread, data, 0, &tid );
1962 This->dp2->dwEnumSessionLock--;
1965 else
1967 /* Invalidate the session cache for the interface */
1968 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
1969 /* Send the broadcast for session enumeration */
1970 hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags, &This->dp2->spData );
1971 SleepEx( timeout, FALSE );
1972 DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
1973 context );
1976 return hr;
1979 static HRESULT WINAPI IDirectPlay2AImpl_GetCaps( IDirectPlay2A *iface, DPCAPS *caps, DWORD flags )
1981 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1982 return IDirectPlayX_GetCaps( &This->IDirectPlay4A_iface, caps, flags );
1985 static HRESULT WINAPI IDirectPlay4AImpl_GetCaps( IDirectPlay4A *iface, DPCAPS *caps, DWORD flags )
1987 return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
1990 static HRESULT WINAPI IDirectPlay4Impl_GetCaps( IDirectPlay4 *iface, DPCAPS *caps, DWORD flags )
1992 return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
1995 static HRESULT WINAPI IDirectPlay2AImpl_GetGroupData( IDirectPlay2A *iface, DPID group, void *data,
1996 DWORD *size, DWORD flags )
1998 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1999 return IDirectPlayX_GetGroupData( &This->IDirectPlay4A_iface, group, data, size, flags );
2002 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupData( IDirectPlay4A *iface, DPID group,
2003 void *data, DWORD *size, DWORD flags )
2005 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2006 return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2009 static HRESULT WINAPI IDirectPlay4Impl_GetGroupData( IDirectPlay4 *iface, DPID group,
2010 void *data, DWORD *size, DWORD flags )
2012 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2013 lpGroupData gdata;
2014 DWORD bufsize;
2015 void *src;
2017 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, group, data, size, flags );
2019 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
2020 return DPERR_INVALIDGROUP;
2022 /* How much buffer is required? */
2023 if ( flags & DPSET_LOCAL )
2025 bufsize = gdata->dwLocalDataSize;
2026 src = gdata->lpLocalData;
2028 else
2030 bufsize = gdata->dwRemoteDataSize;
2031 src = gdata->lpRemoteData;
2034 /* Is the user requesting to know how big a buffer is required? */
2035 if ( !data || *size < bufsize )
2037 *size = bufsize;
2038 return DPERR_BUFFERTOOSMALL;
2041 CopyMemory( data, src, bufsize );
2043 return DP_OK;
2046 static HRESULT DP_IF_GetGroupName( IDirectPlayImpl *This, DPID idGroup, void *lpData,
2047 DWORD *lpdwDataSize, BOOL bAnsi )
2049 lpGroupData lpGData;
2050 LPDPNAME lpName = lpData;
2051 DWORD dwRequiredDataSize;
2053 FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2054 This, idGroup, lpData, lpdwDataSize, bAnsi );
2056 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2058 return DPERR_INVALIDGROUP;
2061 dwRequiredDataSize = lpGData->name.dwSize;
2063 if( lpGData->name.u1.lpszShortNameA )
2065 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2068 if( lpGData->name.u2.lpszLongNameA )
2070 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2073 if( ( lpData == NULL ) ||
2074 ( *lpdwDataSize < dwRequiredDataSize )
2077 *lpdwDataSize = dwRequiredDataSize;
2078 return DPERR_BUFFERTOOSMALL;
2081 /* Copy the structure */
2082 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2084 if( lpGData->name.u1.lpszShortNameA )
2086 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2087 lpGData->name.u1.lpszShortNameA );
2089 else
2091 lpName->u1.lpszShortNameA = NULL;
2094 if( lpGData->name.u1.lpszShortNameA )
2096 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2097 lpGData->name.u2.lpszLongNameA );
2099 else
2101 lpName->u2.lpszLongNameA = NULL;
2104 return DP_OK;
2107 static HRESULT WINAPI IDirectPlay2AImpl_GetGroupName( IDirectPlay2A *iface, DPID group, void *data,
2108 DWORD *size )
2110 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2111 return IDirectPlayX_GetGroupName( &This->IDirectPlay4A_iface, group, data, size );
2114 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupName( IDirectPlay4A *iface, DPID idGroup,
2115 void *lpData, DWORD *lpdwDataSize )
2117 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2118 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2121 static HRESULT WINAPI IDirectPlay4Impl_GetGroupName( IDirectPlay4 *iface, DPID idGroup,
2122 void *lpData, DWORD *lpdwDataSize )
2124 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2125 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2128 static HRESULT WINAPI IDirectPlay2AImpl_GetMessageCount( IDirectPlay2A *iface, DPID player,
2129 DWORD *count )
2131 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2132 return IDirectPlayX_GetMessageCount( &This->IDirectPlay4A_iface, player, count );
2135 static HRESULT WINAPI IDirectPlay4AImpl_GetMessageCount( IDirectPlay4A *iface, DPID player,
2136 DWORD *count )
2138 return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2141 static HRESULT WINAPI IDirectPlay4Impl_GetMessageCount( IDirectPlay4 *iface, DPID player,
2142 DWORD *count )
2144 return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2147 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerAddress( IDirectPlay2A *iface, DPID player,
2148 void *data, DWORD *size )
2150 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2151 return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4A_iface, player, data, size );
2154 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAddress( IDirectPlay4A *iface, DPID player,
2155 void *data, DWORD *size )
2157 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2158 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2159 return DP_OK;
2162 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAddress( IDirectPlay4 *iface, DPID player,
2163 void *data, DWORD *size )
2165 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2166 FIXME( "(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2167 return DP_OK;
2170 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerCaps( IDirectPlay2A *iface, DPID player,
2171 DPCAPS *caps, DWORD flags )
2173 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2174 return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4A_iface, player, caps, flags );
2177 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerCaps( IDirectPlay4A *iface, DPID player,
2178 DPCAPS *caps, DWORD flags )
2180 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2181 return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2184 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerCaps( IDirectPlay4 *iface, DPID player,
2185 DPCAPS *caps, DWORD flags )
2187 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2188 DPSP_GETCAPSDATA data;
2190 TRACE( "(%p)->(0x%08x,%p,0x%08x)\n", This, player, caps, flags);
2192 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2193 return DPERR_UNINITIALIZED;
2195 /* Query the service provider */
2196 data.idPlayer = player;
2197 data.dwFlags = flags;
2198 data.lpCaps = caps;
2199 data.lpISP = This->dp2->spData.lpISP;
2201 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2204 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerData( IDirectPlay2A *iface, DPID player,
2205 void *data, DWORD *size, DWORD flags )
2207 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2208 return IDirectPlayX_GetPlayerData( &This->IDirectPlay4A_iface, player, data, size, flags );
2211 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerData( IDirectPlay4A *iface, DPID player,
2212 void *data, DWORD *size, DWORD flags )
2214 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2215 return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2218 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerData( IDirectPlay4 *iface, DPID player,
2219 void *data, DWORD *size, DWORD flags )
2221 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2222 lpPlayerList plist;
2223 DWORD bufsize;
2224 void *src;
2226 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, player, data, size, flags );
2228 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2229 return DPERR_UNINITIALIZED;
2231 if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
2232 return DPERR_INVALIDPLAYER;
2234 if ( flags & DPSET_LOCAL )
2236 bufsize = plist->lpPData->dwLocalDataSize;
2237 src = plist->lpPData->lpLocalData;
2239 else
2241 bufsize = plist->lpPData->dwRemoteDataSize;
2242 src = plist->lpPData->lpRemoteData;
2245 /* Is the user requesting to know how big a buffer is required? */
2246 if ( !data || *size < bufsize )
2248 *size = bufsize;
2249 return DPERR_BUFFERTOOSMALL;
2252 CopyMemory( data, src, bufsize );
2254 return DP_OK;
2257 static HRESULT DP_IF_GetPlayerName( IDirectPlayImpl *This, DPID idPlayer, void *lpData,
2258 DWORD *lpdwDataSize, BOOL bAnsi )
2260 lpPlayerList lpPList;
2261 LPDPNAME lpName = lpData;
2262 DWORD dwRequiredDataSize;
2264 FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2265 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2267 if( This->dp2->connectionInitialized == NO_PROVIDER )
2269 return DPERR_UNINITIALIZED;
2272 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2274 return DPERR_INVALIDPLAYER;
2277 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2279 if( lpPList->lpPData->name.u1.lpszShortNameA )
2281 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2284 if( lpPList->lpPData->name.u2.lpszLongNameA )
2286 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2289 if( ( lpData == NULL ) ||
2290 ( *lpdwDataSize < dwRequiredDataSize )
2293 *lpdwDataSize = dwRequiredDataSize;
2294 return DPERR_BUFFERTOOSMALL;
2297 /* Copy the structure */
2298 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2300 if( lpPList->lpPData->name.u1.lpszShortNameA )
2302 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2303 lpPList->lpPData->name.u1.lpszShortNameA );
2305 else
2307 lpName->u1.lpszShortNameA = NULL;
2310 if( lpPList->lpPData->name.u1.lpszShortNameA )
2312 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2313 lpPList->lpPData->name.u2.lpszLongNameA );
2315 else
2317 lpName->u2.lpszLongNameA = NULL;
2320 return DP_OK;
2323 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerName( IDirectPlay2A *iface, DPID player,
2324 void *data, DWORD *size )
2326 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2327 return IDirectPlayX_GetPlayerName( &This->IDirectPlay4A_iface, player, data, size );
2330 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
2331 void *lpData, DWORD *lpdwDataSize )
2333 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2334 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2337 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerName( IDirectPlay4 *iface, DPID idPlayer,
2338 void *lpData, DWORD *lpdwDataSize )
2340 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2341 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2344 static HRESULT DP_GetSessionDesc( IDirectPlayImpl *This, void *lpData, DWORD *lpdwDataSize,
2345 BOOL bAnsi )
2347 DWORD dwRequiredSize;
2349 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2351 if( This->dp2->connectionInitialized == NO_PROVIDER )
2353 return DPERR_UNINITIALIZED;
2356 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2358 return DPERR_INVALIDPARAMS;
2361 /* FIXME: Get from This->dp2->lpSessionDesc */
2362 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2364 if ( ( lpData == NULL ) ||
2365 ( *lpdwDataSize < dwRequiredSize )
2368 *lpdwDataSize = dwRequiredSize;
2369 return DPERR_BUFFERTOOSMALL;
2372 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2374 return DP_OK;
2377 static HRESULT WINAPI IDirectPlay2AImpl_GetSessionDesc( IDirectPlay2A *iface, void *data,
2378 DWORD *size )
2380 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2381 return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4A_iface, data, size );
2384 static HRESULT WINAPI IDirectPlay4AImpl_GetSessionDesc( IDirectPlay4A *iface, void *lpData,
2385 DWORD *lpdwDataSize )
2387 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2388 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2391 static HRESULT WINAPI IDirectPlay4Impl_GetSessionDesc( IDirectPlay4 *iface, void *lpData,
2392 DWORD *lpdwDataSize )
2394 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2395 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2398 static HRESULT WINAPI IDirectPlay2AImpl_Initialize( IDirectPlay2A *iface, GUID *guid )
2400 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2401 return IDirectPlayX_Initialize( &This->IDirectPlay4A_iface, guid );
2404 /* Intended only for COM compatibility. Always returns an error. */
2405 static HRESULT WINAPI IDirectPlay4AImpl_Initialize( IDirectPlay4A *iface, GUID *guid )
2407 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2408 TRACE("(%p)->(%p): no-op\n", This, guid );
2409 return DPERR_ALREADYINITIALIZED;
2412 static HRESULT WINAPI IDirectPlay4Impl_Initialize( IDirectPlay4 *iface, GUID *guid )
2414 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2415 TRACE( "(%p)->(%p): no-op\n", This, guid );
2416 return DPERR_ALREADYINITIALIZED;
2420 static HRESULT DP_SecureOpen( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpsd, DWORD dwFlags,
2421 const DPSECURITYDESC *lpSecurity, const DPCREDENTIALS *lpCredentials, BOOL bAnsi )
2423 HRESULT hr = DP_OK;
2425 FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2426 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2428 if( This->dp2->connectionInitialized == NO_PROVIDER )
2430 return DPERR_UNINITIALIZED;
2433 if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
2435 TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
2436 return DPERR_INVALIDPARAMS;
2439 if( This->dp2->bConnectionOpen )
2441 TRACE( ": rejecting already open connection.\n" );
2442 return DPERR_ALREADYINITIALIZED;
2445 /* If we're enumerating, kill the thread */
2446 DP_KillEnumSessionThread( This );
2448 if( dwFlags & DPOPEN_CREATE )
2450 /* Rightoo - this computer is the host and the local computer needs to be
2451 the name server so that others can join this session */
2452 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2454 This->dp2->bHostInterface = TRUE;
2456 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2457 if( FAILED( hr ) )
2459 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2460 return hr;
2464 /* Invoke the conditional callback for the service provider */
2465 if( This->dp2->spData.lpCB->Open )
2467 DPSP_OPENDATA data;
2469 FIXME( "Not all data fields are correct. Need new parameter\n" );
2471 data.bCreate = (dwFlags & DPOPEN_CREATE ) != 0;
2472 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2473 : NS_GetNSAddr( This->dp2->lpNameServerData );
2474 data.lpISP = This->dp2->spData.lpISP;
2475 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) != 0;
2476 data.dwOpenFlags = dwFlags;
2477 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2479 hr = (*This->dp2->spData.lpCB->Open)(&data);
2480 if( FAILED( hr ) )
2482 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2483 return hr;
2488 /* Create the system group of which everything is a part of */
2489 DPID systemGroup = DPID_SYSTEM_GROUP;
2491 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2492 NULL, 0, 0, TRUE );
2496 if( dwFlags & DPOPEN_JOIN )
2498 DPID dpidServerId = DPID_UNKNOWN;
2500 /* Create the server player for this interface. This way we can receive
2501 * messages for this session.
2503 /* FIXME: I suppose that we should be setting an event for a receive
2504 * type of thing. That way the messaging thread could know to wake
2505 * up. DPlay would then trigger the hEvent for the player the
2506 * message is directed to.
2508 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2510 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2513 else if( dwFlags & DPOPEN_CREATE )
2515 DPID dpidNameServerId = DPID_NAME_SERVER;
2517 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2518 0, DPPLAYER_SERVERPLAYER, bAnsi );
2521 if( FAILED(hr) )
2523 ERR( "Couldn't create name server/system player: %s\n",
2524 DPLAYX_HresultToString(hr) );
2527 return hr;
2530 static HRESULT WINAPI IDirectPlay2AImpl_Open( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
2531 DWORD flags )
2533 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2534 return IDirectPlayX_Open( &This->IDirectPlay4A_iface, sdesc, flags );
2537 static HRESULT WINAPI IDirectPlay4AImpl_Open( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
2538 DWORD flags )
2540 return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
2543 static HRESULT WINAPI IDirectPlay4Impl_Open( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
2544 DWORD flags )
2546 return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
2549 static HRESULT DP_IF_Receive( IDirectPlayImpl *This, DPID *lpidFrom, DPID *lpidTo, DWORD dwFlags,
2550 void *lpData, DWORD *lpdwDataSize, BOOL bAnsi )
2552 LPDPMSG lpMsg = NULL;
2554 FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
2555 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2557 if( This->dp2->connectionInitialized == NO_PROVIDER )
2559 return DPERR_UNINITIALIZED;
2562 if( dwFlags == 0 )
2564 dwFlags = DPRECEIVE_ALL;
2567 /* If the lpData is NULL, we must be peeking the message */
2568 if( ( lpData == NULL ) &&
2569 !( dwFlags & DPRECEIVE_PEEK )
2572 return DPERR_INVALIDPARAMS;
2575 if( dwFlags & DPRECEIVE_ALL )
2577 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2579 if( !( dwFlags & DPRECEIVE_PEEK ) )
2581 FIXME( "Remove from queue\n" );
2584 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2585 ( dwFlags & DPRECEIVE_FROMPLAYER )
2588 FIXME( "Find matching message 0x%08x\n", dwFlags );
2590 else
2592 ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
2595 if( lpMsg == NULL )
2597 return DPERR_NOMESSAGES;
2600 /* Copy into the provided buffer */
2601 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
2603 return DP_OK;
2606 static HRESULT WINAPI IDirectPlay2AImpl_Receive( IDirectPlay2A *iface, DPID *from, DPID *to,
2607 DWORD flags, void *data, DWORD *size )
2609 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2610 return IDirectPlayX_Receive( &This->IDirectPlay4A_iface, from, to, flags, data, size );
2613 static HRESULT WINAPI IDirectPlay4AImpl_Receive( IDirectPlay4A *iface, DPID *lpidFrom,
2614 DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
2616 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2617 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, TRUE );
2620 static HRESULT WINAPI IDirectPlay4Impl_Receive( IDirectPlay4 *iface, DPID *lpidFrom,
2621 DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
2623 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2624 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, FALSE );
2627 static HRESULT WINAPI IDirectPlay2AImpl_Send( IDirectPlay2A *iface, DPID from, DPID to,
2628 DWORD flags, void *data, DWORD size )
2630 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2631 return IDirectPlayX_Send( &This->IDirectPlay4A_iface, from, to, flags, data, size );
2634 static HRESULT WINAPI IDirectPlay4AImpl_Send( IDirectPlay4A *iface, DPID from, DPID to,
2635 DWORD flags, void *data, DWORD size )
2637 return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
2640 static HRESULT WINAPI IDirectPlay4Impl_Send( IDirectPlay4 *iface, DPID from, DPID to,
2641 DWORD flags, void *data, DWORD size )
2643 return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
2646 static HRESULT WINAPI IDirectPlay2AImpl_SetGroupData( IDirectPlay2A *iface, DPID group, void *data,
2647 DWORD size, DWORD flags )
2649 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2650 return IDirectPlayX_SetGroupData( &This->IDirectPlay4A_iface, group, data, size, flags );
2653 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupData( IDirectPlay4A *iface, DPID group, void *data,
2654 DWORD size, DWORD flags )
2656 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2657 return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2660 static HRESULT WINAPI IDirectPlay4Impl_SetGroupData( IDirectPlay4 *iface, DPID group, void *data,
2661 DWORD size, DWORD flags )
2663 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2664 lpGroupData gdata;
2666 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, group, data, size, flags );
2668 /* Parameter check */
2669 if ( !data && size )
2670 return DPERR_INVALIDPARAMS;
2672 /* Find the pointer to the data for this player */
2673 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
2674 return DPERR_INVALIDOBJECT;
2676 if ( !(flags & DPSET_LOCAL) )
2678 FIXME( "Was this group created by this interface?\n" );
2679 /* FIXME: If this is a remote update need to allow it but not
2680 * send a message.
2684 DP_SetGroupData( gdata, flags, data, size );
2686 /* FIXME: Only send a message if this group is local to the session otherwise
2687 * it will have been rejected above
2689 if ( !(flags & DPSET_LOCAL) )
2690 FIXME( "Send msg?\n" );
2692 return DP_OK;
2695 static HRESULT DP_IF_SetGroupName( IDirectPlayImpl *This, DPID idGroup, DPNAME *lpGroupName,
2696 DWORD dwFlags, BOOL bAnsi )
2698 lpGroupData lpGData;
2700 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
2701 lpGroupName, dwFlags, bAnsi );
2703 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2705 return DPERR_INVALIDGROUP;
2708 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
2710 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
2711 FIXME( "Message not sent and dwFlags ignored\n" );
2713 return DP_OK;
2716 static HRESULT WINAPI IDirectPlay2AImpl_SetGroupName( IDirectPlay2A *iface, DPID group,
2717 DPNAME *name, DWORD flags )
2719 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2720 return IDirectPlayX_SetGroupName( &This->IDirectPlay4A_iface, group, name, flags );
2723 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupName( IDirectPlay4A *iface, DPID idGroup,
2724 DPNAME *lpGroupName, DWORD dwFlags )
2726 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2727 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
2730 static HRESULT WINAPI IDirectPlay4Impl_SetGroupName( IDirectPlay4 *iface, DPID idGroup,
2731 DPNAME *lpGroupName, DWORD dwFlags )
2733 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2734 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
2737 static HRESULT WINAPI IDirectPlay2AImpl_SetPlayerData( IDirectPlay2A *iface, DPID player,
2738 void *data, DWORD size, DWORD flags )
2740 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2741 return IDirectPlayX_SetPlayerData( &This->IDirectPlay4A_iface, player, data, size, flags );
2744 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerData( IDirectPlay4A *iface, DPID player,
2745 void *data, DWORD size, DWORD flags )
2747 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2748 return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2751 static HRESULT WINAPI IDirectPlay4Impl_SetPlayerData( IDirectPlay4 *iface, DPID player,
2752 void *data, DWORD size, DWORD flags )
2754 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2755 lpPlayerList plist;
2757 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, player, data, size, flags );
2759 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2760 return DPERR_UNINITIALIZED;
2762 /* Parameter check */
2763 if ( !data && size )
2764 return DPERR_INVALIDPARAMS;
2766 /* Find the pointer to the data for this player */
2767 if ( (plist = DP_FindPlayer( This, player )) == NULL )
2768 return DPERR_INVALIDPLAYER;
2770 if ( !(flags & DPSET_LOCAL) )
2772 FIXME( "Was this group created by this interface?\n" );
2773 /* FIXME: If this is a remote update need to allow it but not
2774 * send a message.
2778 DP_SetPlayerData( plist->lpPData, flags, data, size );
2780 if ( !(flags & DPSET_LOCAL) )
2781 FIXME( "Send msg?\n" );
2783 return DP_OK;
2786 static HRESULT DP_IF_SetPlayerName( IDirectPlayImpl *This, DPID idPlayer, DPNAME *lpPlayerName,
2787 DWORD dwFlags, BOOL bAnsi )
2789 lpPlayerList lpPList;
2791 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
2792 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
2794 if( This->dp2->connectionInitialized == NO_PROVIDER )
2796 return DPERR_UNINITIALIZED;
2799 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2801 return DPERR_INVALIDGROUP;
2804 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
2806 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
2807 FIXME( "Message not sent and dwFlags ignored\n" );
2809 return DP_OK;
2812 static HRESULT WINAPI IDirectPlay2AImpl_SetPlayerName( IDirectPlay2A *iface, DPID player,
2813 DPNAME *name, DWORD flags )
2815 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2816 return IDirectPlayX_SetPlayerName( &This->IDirectPlay4A_iface, player, name, flags );
2819 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
2820 DPNAME *lpPlayerName, DWORD dwFlags )
2822 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2823 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
2826 static HRESULT WINAPI IDirectPlay4Impl_SetPlayerName( IDirectPlay4 *iface, DPID idPlayer,
2827 DPNAME *lpPlayerName, DWORD dwFlags )
2829 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2830 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
2833 static HRESULT DP_SetSessionDesc( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpSessDesc,
2834 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
2836 DWORD dwRequiredSize;
2837 LPDPSESSIONDESC2 lpTempSessDesc;
2839 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
2840 This, lpSessDesc, dwFlags, bInitial, bAnsi );
2842 if( This->dp2->connectionInitialized == NO_PROVIDER )
2844 return DPERR_UNINITIALIZED;
2847 if( dwFlags )
2849 return DPERR_INVALIDPARAMS;
2852 /* Only the host is allowed to update the session desc */
2853 if( !This->dp2->bHostInterface )
2855 return DPERR_ACCESSDENIED;
2858 /* FIXME: Copy into This->dp2->lpSessionDesc */
2859 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
2860 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
2862 if( lpTempSessDesc == NULL )
2864 return DPERR_OUTOFMEMORY;
2867 /* Free the old */
2868 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
2870 This->dp2->lpSessionDesc = lpTempSessDesc;
2871 /* Set the new */
2872 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
2873 if( bInitial )
2875 /*Initializing session GUID*/
2876 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
2878 /* If this is an external invocation of the interface, we should be
2879 * letting everyone know that things have changed. Otherwise this is
2880 * just an initialization and it doesn't need to be propagated.
2882 if( !bInitial )
2884 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
2887 return DP_OK;
2890 static HRESULT WINAPI IDirectPlay2AImpl_SetSessionDesc( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
2891 DWORD flags )
2893 IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2894 return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4A_iface, sdesc, flags );
2897 static HRESULT WINAPI IDirectPlay4AImpl_SetSessionDesc( IDirectPlay4A *iface,
2898 DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
2900 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2901 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
2904 static HRESULT WINAPI IDirectPlay4Impl_SetSessionDesc( IDirectPlay4 *iface,
2905 DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
2907 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2908 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
2911 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
2912 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
2914 DWORD dwSize = 0;
2916 if( lpSessDesc == NULL )
2918 /* Hmmm..don't need any size? */
2919 ERR( "NULL lpSessDesc\n" );
2920 return dwSize;
2923 dwSize += sizeof( *lpSessDesc );
2925 if( bAnsi )
2927 if( lpSessDesc->u1.lpszSessionNameA )
2929 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
2932 if( lpSessDesc->u2.lpszPasswordA )
2934 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
2937 else /* UNICODE */
2939 if( lpSessDesc->u1.lpszSessionName )
2941 dwSize += sizeof( WCHAR ) *
2942 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
2945 if( lpSessDesc->u2.lpszPassword )
2947 dwSize += sizeof( WCHAR ) *
2948 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
2952 return dwSize;
2955 /* Assumes that contiguous buffers are already allocated. */
2956 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
2957 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
2959 BYTE* lpStartOfFreeSpace;
2961 if( lpSessionDest == NULL )
2963 ERR( "NULL lpSessionDest\n" );
2964 return;
2967 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
2969 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
2971 if( bAnsi )
2973 if( lpSessionSrc->u1.lpszSessionNameA )
2975 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
2976 lpSessionDest->u1.lpszSessionNameA );
2977 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
2978 lpStartOfFreeSpace +=
2979 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
2982 if( lpSessionSrc->u2.lpszPasswordA )
2984 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
2985 lpSessionDest->u2.lpszPasswordA );
2986 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
2989 else /* UNICODE */
2991 if( lpSessionSrc->u1.lpszSessionName )
2993 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
2994 lpSessionDest->u1.lpszSessionName );
2995 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
2996 lpStartOfFreeSpace += sizeof(WCHAR) *
2997 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3000 if( lpSessionSrc->u2.lpszPassword )
3002 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3003 lpSessionDest->u2.lpszPassword );
3004 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3009 static HRESULT WINAPI IDirectPlay4AImpl_AddGroupToGroup( IDirectPlay4A *iface, DPID parent,
3010 DPID group )
3012 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3013 return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
3016 static HRESULT WINAPI IDirectPlay4Impl_AddGroupToGroup( IDirectPlay4 *iface, DPID parent,
3017 DPID group )
3019 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3020 lpGroupData gdata;
3021 lpGroupList glist;
3023 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, parent, group );
3025 if ( This->dp2->connectionInitialized == NO_PROVIDER )
3026 return DPERR_UNINITIALIZED;
3028 if ( !DP_FindAnyGroup(This, parent ) )
3029 return DPERR_INVALIDGROUP;
3031 if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
3032 return DPERR_INVALIDGROUP;
3034 /* Create a player list (ie "shortcut" ) */
3035 glist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *glist ) );
3036 if ( !glist )
3037 return DPERR_CANTADDPLAYER;
3039 /* Add the shortcut */
3040 gdata->uRef++;
3041 glist->lpGData = gdata;
3043 /* Add the player to the list of players for this group */
3044 DPQ_INSERT( gdata->groups, glist, groups );
3046 /* Send a ADDGROUPTOGROUP message */
3047 FIXME( "Not sending message\n" );
3049 return DP_OK;
3052 static HRESULT DP_IF_CreateGroupInGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID idParentGroup,
3053 DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags,
3054 BOOL bAnsi )
3056 lpGroupData lpGParentData;
3057 lpGroupList lpGList;
3058 lpGroupData lpGData;
3060 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3061 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3062 dwDataSize, dwFlags, bAnsi );
3064 if( This->dp2->connectionInitialized == NO_PROVIDER )
3066 return DPERR_UNINITIALIZED;
3069 /* Verify that the specified parent is valid */
3070 if( ( lpGParentData = DP_FindAnyGroup(This, idParentGroup ) ) == NULL )
3071 return DPERR_INVALIDGROUP;
3073 lpGData = DP_CreateGroup(This, lpidGroup, lpGroupName, dwFlags, idParentGroup, bAnsi );
3075 if( lpGData == NULL )
3077 return DPERR_CANTADDPLAYER; /* yes player not group */
3080 /* Something else is referencing this data */
3081 lpGData->uRef++;
3083 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3085 /* The list has now been inserted into the interface group list. We now
3086 need to put a "shortcut" to this group in the parent group */
3087 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3088 if( lpGList == NULL )
3090 FIXME( "Memory leak\n" );
3091 return DPERR_CANTADDPLAYER; /* yes player not group */
3094 lpGList->lpGData = lpGData;
3096 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3098 /* Let the SP know that we've created this group */
3099 if( This->dp2->spData.lpCB->CreateGroup )
3101 DPSP_CREATEGROUPDATA data;
3103 TRACE( "Calling SP CreateGroup\n" );
3105 data.idGroup = *lpidGroup;
3106 data.dwFlags = dwFlags;
3107 data.lpSPMessageHeader = lpMsgHdr;
3108 data.lpISP = This->dp2->spData.lpISP;
3110 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3113 /* Inform all other peers of the creation of a new group. If there are
3114 * no peers keep this quiet.
3116 if( This->dp2->lpSessionDesc &&
3117 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3119 DPMSG_CREATEPLAYERORGROUP msg;
3121 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3122 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3123 msg.dpId = *lpidGroup;
3124 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3125 msg.lpData = lpData;
3126 msg.dwDataSize = dwDataSize;
3127 msg.dpnName = *lpGroupName;
3129 /* FIXME: Correct to just use send effectively? */
3130 /* FIXME: Should size include data w/ message or just message "header" */
3131 /* FIXME: Check return code */
3132 IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
3133 sizeof( msg ), 0, 0, NULL, NULL );
3136 return DP_OK;
3139 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroupInGroup( IDirectPlay4A *iface,
3140 DPID idParentGroup, DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize,
3141 DWORD dwFlags )
3143 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3145 *lpidGroup = DPID_UNKNOWN;
3147 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
3148 dwDataSize, dwFlags, TRUE );
3151 static HRESULT WINAPI IDirectPlay4Impl_CreateGroupInGroup( IDirectPlay4 *iface, DPID idParentGroup,
3152 DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
3154 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3156 *lpidGroup = DPID_UNKNOWN;
3158 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
3159 dwDataSize, dwFlags, FALSE );
3162 static HRESULT WINAPI IDirectPlay4AImpl_DeleteGroupFromGroup( IDirectPlay4A *iface, DPID parent,
3163 DPID group )
3165 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3166 return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
3169 static HRESULT WINAPI IDirectPlay4Impl_DeleteGroupFromGroup( IDirectPlay4 *iface, DPID parent,
3170 DPID group )
3172 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3173 lpGroupList glist;
3174 lpGroupData parentdata;
3176 TRACE("(%p)->(0x%08x,0x%08x)\n", This, parent, group );
3178 /* Is the parent group valid? */
3179 if ( ( parentdata = DP_FindAnyGroup(This, parent ) ) == NULL )
3180 return DPERR_INVALIDGROUP;
3182 /* Remove the group from the parent group queue */
3183 DPQ_REMOVE_ENTRY( parentdata->groups, groups, lpGData->dpid, ==, group, glist );
3185 if ( glist == NULL )
3186 return DPERR_INVALIDGROUP;
3188 /* Decrement the ref count */
3189 glist->lpGData->uRef--;
3191 /* Free up the list item */
3192 HeapFree( GetProcessHeap(), 0, glist );
3194 /* Should send a DELETEGROUPFROMGROUP message */
3195 FIXME( "message not sent\n" );
3197 return DP_OK;
3200 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3201 LPDWORD lpdwBufSize )
3203 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3204 HRESULT hr;
3206 dpCompoundAddress.dwDataSize = sizeof( GUID );
3207 dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3208 dpCompoundAddress.lpData = lpcSpGuid;
3210 *lplpAddrBuf = NULL;
3211 *lpdwBufSize = 0;
3213 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3214 lpdwBufSize, TRUE );
3216 if( hr != DPERR_BUFFERTOOSMALL )
3218 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3219 return FALSE;
3222 /* Now allocate the buffer */
3223 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3224 *lpdwBufSize );
3226 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3227 lpdwBufSize, TRUE );
3228 if( FAILED(hr) )
3230 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3231 return FALSE;
3234 return TRUE;
3237 static HRESULT WINAPI IDirectPlay4AImpl_EnumConnections( IDirectPlay4A *iface,
3238 const GUID *lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, void *lpContext,
3239 DWORD dwFlags )
3241 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3242 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3244 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3245 if( dwFlags == 0 )
3247 dwFlags = DPCONNECTION_DIRECTPLAY;
3250 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3251 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3254 return DPERR_INVALIDFLAGS;
3257 if( !lpEnumCallback )
3259 return DPERR_INVALIDPARAMS;
3262 /* Enumerate DirectPlay service providers */
3263 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3265 HKEY hkResult;
3266 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3267 LPCSTR guidDataSubKey = "Guid";
3268 char subKeyName[51];
3269 DWORD dwIndex, sizeOfSubKeyName=50;
3270 FILETIME filetime;
3272 /* Need to loop over the service providers in the registry */
3273 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3274 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3276 /* Hmmm. Does this mean that there are no service providers? */
3277 ERR(": no service providers?\n");
3278 return DP_OK;
3282 /* Traverse all the service providers we have available */
3283 for( dwIndex=0;
3284 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3285 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3286 ++dwIndex, sizeOfSubKeyName=51 )
3289 HKEY hkServiceProvider;
3290 GUID serviceProviderGUID;
3291 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3292 char returnBuffer[51];
3293 WCHAR buff[51];
3294 DPNAME dpName;
3295 BOOL bBuildPass;
3297 LPVOID lpAddressBuffer = NULL;
3298 DWORD dwAddressBufferSize = 0;
3300 TRACE(" this time through: %s\n", subKeyName );
3302 /* Get a handle for this particular service provider */
3303 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3304 &hkServiceProvider ) != ERROR_SUCCESS )
3306 ERR(": what the heck is going on?\n" );
3307 continue;
3310 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3311 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3312 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3314 ERR(": missing GUID registry data members\n" );
3315 RegCloseKey(hkServiceProvider);
3316 continue;
3318 RegCloseKey(hkServiceProvider);
3320 /* FIXME: Check return types to ensure we're interpreting data right */
3321 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3322 CLSIDFromString( buff, &serviceProviderGUID );
3323 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3325 /* Fill in the DPNAME struct for the service provider */
3326 dpName.dwSize = sizeof( dpName );
3327 dpName.dwFlags = 0;
3328 dpName.u1.lpszShortNameA = subKeyName;
3329 dpName.u2.lpszLongNameA = NULL;
3331 /* Create the compound address for the service provider.
3332 * NOTE: This is a gruesome architectural scar right now. DP
3333 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3334 * native dll just gets around this little bit by allocating an
3335 * 80 byte buffer which isn't even filled with a valid compound
3336 * address. Oh well. Creating a proper compound address is the
3337 * way to go anyways despite this method taking slightly more
3338 * heap space and realtime :) */
3340 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3341 &lpAddressBuffer,
3342 &dwAddressBufferSize );
3343 if( !bBuildPass )
3345 ERR( "Can't build compound addr\n" );
3346 return DPERR_GENERIC;
3349 /* The enumeration will return FALSE if we are not to continue */
3350 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3351 &dpName, dwFlags, lpContext ) )
3353 return DP_OK;
3358 /* Enumerate DirectPlayLobby service providers */
3359 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3361 HKEY hkResult;
3362 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3363 LPCSTR guidDataSubKey = "Guid";
3364 char subKeyName[51];
3365 DWORD dwIndex, sizeOfSubKeyName=50;
3366 FILETIME filetime;
3368 /* Need to loop over the service providers in the registry */
3369 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3370 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3372 /* Hmmm. Does this mean that there are no service providers? */
3373 ERR(": no service providers?\n");
3374 return DP_OK;
3378 /* Traverse all the lobby providers we have available */
3379 for( dwIndex=0;
3380 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3381 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3382 ++dwIndex, sizeOfSubKeyName=51 )
3385 HKEY hkServiceProvider;
3386 GUID serviceProviderGUID;
3387 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3388 char returnBuffer[51];
3389 WCHAR buff[51];
3390 DPNAME dpName;
3391 HRESULT hr;
3393 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3394 LPVOID lpAddressBuffer = NULL;
3395 DWORD dwAddressBufferSize = 0;
3397 TRACE(" this time through: %s\n", subKeyName );
3399 /* Get a handle for this particular service provider */
3400 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3401 &hkServiceProvider ) != ERROR_SUCCESS )
3403 ERR(": what the heck is going on?\n" );
3404 continue;
3407 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3408 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3409 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3411 ERR(": missing GUID registry data members\n" );
3412 RegCloseKey(hkServiceProvider);
3413 continue;
3415 RegCloseKey(hkServiceProvider);
3417 /* FIXME: Check return types to ensure we're interpreting data right */
3418 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3419 CLSIDFromString( buff, &serviceProviderGUID );
3420 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3422 /* Fill in the DPNAME struct for the service provider */
3423 dpName.dwSize = sizeof( dpName );
3424 dpName.dwFlags = 0;
3425 dpName.u1.lpszShortNameA = subKeyName;
3426 dpName.u2.lpszLongNameA = NULL;
3428 /* Create the compound address for the service provider.
3429 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3430 nast stuff. This may be why the native dll just gets around this little bit by
3431 allocating an 80 byte buffer which isn't even a filled with a valid compound
3432 address. Oh well. Creating a proper compound address is the way to go anyways
3433 despite this method taking slightly more heap space and realtime :) */
3435 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3436 dpCompoundAddress.dwDataSize = sizeof( GUID );
3437 dpCompoundAddress.lpData = &serviceProviderGUID;
3439 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3440 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3442 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3443 return hr;
3446 /* Now allocate the buffer */
3447 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3449 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3450 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3452 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3453 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3454 return hr;
3457 /* The enumeration will return FALSE if we are not to continue */
3458 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3459 &dpName, dwFlags, lpContext ) )
3461 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3462 return DP_OK;
3464 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3468 return DP_OK;
3471 static HRESULT WINAPI IDirectPlay4Impl_EnumConnections( IDirectPlay4 *iface,
3472 const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
3474 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3475 FIXME( "(%p)->(%p,%p,%p,0x%08x): stub\n", This, application, enumcb, context, flags );
3476 return DP_OK;
3479 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupsInGroup( IDirectPlay4A *iface, DPID group,
3480 GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
3482 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3483 return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, group, instance,
3484 enumplayercb, context, flags );
3487 static HRESULT WINAPI IDirectPlay4Impl_EnumGroupsInGroup( IDirectPlay4 *iface, DPID group,
3488 GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
3490 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3491 lpGroupList glist;
3492 lpGroupData gdata;
3494 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
3495 context, flags );
3497 if ( This->dp2->connectionInitialized == NO_PROVIDER )
3498 return DPERR_UNINITIALIZED;
3500 if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
3501 return DPERR_INVALIDGROUP;
3503 if ( DPQ_IS_EMPTY( gdata->groups ) )
3504 return DP_OK;
3507 for( glist = DPQ_FIRST( gdata->groups ); ; glist = DPQ_NEXT( glist->groups ) )
3509 /* FIXME: Should check flags for match here */
3510 if ( !(*enumplayercb)( glist->lpGData->dpid, DPPLAYERTYPE_GROUP, &glist->lpGData->name,
3511 flags, context ) )
3512 return DP_OK; /* User requested break */
3514 if ( DPQ_IS_ENDOFLIST( glist->groups ) )
3515 break;
3518 return DP_OK;
3521 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupConnectionSettings( IDirectPlay4A *iface,
3522 DWORD flags, DPID group, void *data, DWORD *size )
3524 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3525 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
3526 return DP_OK;
3529 static HRESULT WINAPI IDirectPlay4Impl_GetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
3530 DPID group, void *data, DWORD *size )
3532 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3533 FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
3534 return DP_OK;
3537 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
3538 REFGUID guidDataType,
3539 DWORD dwDataSize,
3540 LPCVOID lpData,
3541 LPVOID lpContext )
3543 /* Looking for the GUID of the provider to load */
3544 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
3545 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
3548 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
3549 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
3551 if( dwDataSize != sizeof( GUID ) )
3553 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
3556 memcpy( lpContext, lpData, dwDataSize );
3558 /* There shouldn't be more than 1 GUID/compound address */
3559 return FALSE;
3562 /* Still waiting for what we want */
3563 return TRUE;
3567 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
3568 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
3570 UINT i;
3571 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3572 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3573 LPCSTR guidDataSubKey = "Guid";
3574 LPCSTR majVerDataSubKey = "dwReserved1";
3575 LPCSTR minVerDataSubKey = "dwReserved2";
3576 LPCSTR pathSubKey = "Path";
3578 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
3580 /* FIXME: Cloned code with a quick hack. */
3581 for( i=0; i<2; i++ )
3583 HKEY hkResult;
3584 LPCSTR searchSubKey;
3585 char subKeyName[51];
3586 DWORD dwIndex, sizeOfSubKeyName=50;
3587 FILETIME filetime;
3589 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
3590 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
3593 /* Need to loop over the service providers in the registry */
3594 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3595 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3597 /* Hmmm. Does this mean that there are no service providers? */
3598 ERR(": no service providers?\n");
3599 return 0;
3602 /* Traverse all the service providers we have available */
3603 for( dwIndex=0;
3604 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3605 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3606 ++dwIndex, sizeOfSubKeyName=51 )
3609 HKEY hkServiceProvider;
3610 GUID serviceProviderGUID;
3611 DWORD returnType, sizeOfReturnBuffer = 255;
3612 char returnBuffer[256];
3613 WCHAR buff[51];
3614 DWORD dwTemp, len;
3616 TRACE(" this time through: %s\n", subKeyName );
3618 /* Get a handle for this particular service provider */
3619 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3620 &hkServiceProvider ) != ERROR_SUCCESS )
3622 ERR(": what the heck is going on?\n" );
3623 continue;
3626 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3627 NULL, &returnType, (LPBYTE)returnBuffer,
3628 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3630 ERR(": missing GUID registry data members\n" );
3631 continue;
3634 /* FIXME: Check return types to ensure we're interpreting data right */
3635 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3636 CLSIDFromString( buff, &serviceProviderGUID );
3637 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3639 /* Determine if this is the Service Provider that the user asked for */
3640 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
3642 continue;
3645 if( i == 0 ) /* DP SP */
3647 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
3648 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
3649 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
3652 sizeOfReturnBuffer = 255;
3654 /* Get dwReserved1 */
3655 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
3656 NULL, &returnType, (LPBYTE)returnBuffer,
3657 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3659 ERR(": missing dwReserved1 registry data members\n") ;
3660 continue;
3663 if( i == 0 )
3664 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
3666 sizeOfReturnBuffer = 255;
3668 /* Get dwReserved2 */
3669 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
3670 NULL, &returnType, (LPBYTE)returnBuffer,
3671 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3673 ERR(": missing dwReserved1 registry data members\n") ;
3674 continue;
3677 if( i == 0 )
3678 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
3680 sizeOfReturnBuffer = 255;
3682 /* Get the path for this service provider */
3683 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
3684 NULL, NULL, (LPBYTE)returnBuffer,
3685 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
3687 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
3688 continue;
3691 TRACE( "Loading %s\n", returnBuffer );
3692 return LoadLibraryA( returnBuffer );
3696 return 0;
3699 static HRESULT DP_InitializeDPSP( IDirectPlayImpl *This, HMODULE hServiceProvider )
3701 HRESULT hr;
3702 LPDPSP_SPINIT SPInit;
3704 /* Initialize the service provider by calling SPInit */
3705 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
3707 if( SPInit == NULL )
3709 ERR( "Service provider doesn't provide SPInit interface?\n" );
3710 FreeLibrary( hServiceProvider );
3711 return DPERR_UNAVAILABLE;
3714 TRACE( "Calling SPInit (DP SP entry point)\n" );
3716 hr = (*SPInit)( &This->dp2->spData );
3718 if( FAILED(hr) )
3720 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
3721 FreeLibrary( hServiceProvider );
3722 return hr;
3725 /* FIXME: Need to verify the sanity of the returned callback table
3726 * using IsBadCodePtr */
3727 This->dp2->bSPInitialized = TRUE;
3729 /* This interface is now initialized as a DP object */
3730 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
3732 /* Store the handle of the module so that we can unload it later */
3733 This->dp2->hServiceProvider = hServiceProvider;
3735 return hr;
3738 static HRESULT DP_InitializeDPLSP( IDirectPlayImpl *This, HMODULE hLobbyProvider )
3740 HRESULT hr;
3741 LPSP_INIT DPLSPInit;
3743 /* Initialize the service provider by calling SPInit */
3744 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
3746 if( DPLSPInit == NULL )
3748 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
3749 FreeLibrary( hLobbyProvider );
3750 return DPERR_UNAVAILABLE;
3753 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
3755 hr = (*DPLSPInit)( &This->dp2->dplspData );
3757 if( FAILED(hr) )
3759 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
3760 FreeLibrary( hLobbyProvider );
3761 return hr;
3764 /* FIXME: Need to verify the sanity of the returned callback table
3765 * using IsBadCodePtr */
3767 This->dp2->bDPLSPInitialized = TRUE;
3769 /* This interface is now initialized as a lobby object */
3770 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
3772 /* Store the handle of the module so that we can unload it later */
3773 This->dp2->hDPLobbyProvider = hLobbyProvider;
3775 return hr;
3778 static HRESULT WINAPI IDirectPlay4AImpl_InitializeConnection( IDirectPlay4A *iface,
3779 void *connection, DWORD flags )
3781 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3782 return IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, flags );
3785 static HRESULT WINAPI IDirectPlay4Impl_InitializeConnection( IDirectPlay4 *iface,
3786 void *connection, DWORD flags )
3788 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3789 HMODULE servprov;
3790 GUID sp;
3791 const DWORD size = 80; /* FIXME: Need to calculate it correctly */
3792 BOOL is_dp_sp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
3793 HRESULT hr;
3795 TRACE( "(%p)->(%p,0x%08x)\n", This, connection, flags );
3797 if ( !connection )
3798 return DPERR_INVALIDPARAMS;
3800 if ( flags )
3801 return DPERR_INVALIDFLAGS;
3803 if ( This->dp2->connectionInitialized != NO_PROVIDER )
3804 return DPERR_ALREADYINITIALIZED;
3806 /* Find out what the requested SP is and how large this buffer is */
3807 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, connection, size, &sp );
3809 if ( FAILED(hr) )
3811 ERR( "Invalid compound address?\n" );
3812 return DPERR_UNAVAILABLE;
3815 /* Load the service provider */
3816 servprov = DP_LoadSP( &sp, &This->dp2->spData, &is_dp_sp );
3818 if ( !servprov )
3820 ERR( "Unable to load service provider %s\n", debugstr_guid(&sp) );
3821 return DPERR_UNAVAILABLE;
3824 if ( is_dp_sp )
3826 /* Fill in what we can of the Service Provider required information.
3827 * The rest was be done in DP_LoadSP
3829 This->dp2->spData.lpAddress = connection;
3830 This->dp2->spData.dwAddressSize = size;
3831 This->dp2->spData.lpGuid = &sp;
3832 hr = DP_InitializeDPSP( This, servprov );
3834 else
3836 This->dp2->dplspData.lpAddress = connection;
3837 hr = DP_InitializeDPLSP( This, servprov );
3840 if ( FAILED(hr) )
3841 return hr;
3843 return DP_OK;
3846 static HRESULT WINAPI IDirectPlay4AImpl_SecureOpen( IDirectPlay4A *iface,
3847 const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
3848 const DPCREDENTIALS *lpCredentials )
3850 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3851 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
3854 static HRESULT WINAPI IDirectPlay4Impl_SecureOpen( IDirectPlay4 *iface,
3855 const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
3856 const DPCREDENTIALS *lpCredentials )
3858 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3859 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
3862 static HRESULT WINAPI IDirectPlay4AImpl_SendChatMessage( IDirectPlay4A *iface, DPID from,
3863 DPID to, DWORD flags, DPCHAT *chatmsg )
3865 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3866 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
3867 return DP_OK;
3870 static HRESULT WINAPI IDirectPlay4Impl_SendChatMessage( IDirectPlay4 *iface, DPID from, DPID to,
3871 DWORD flags, DPCHAT *chatmsg )
3873 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3874 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
3875 return DP_OK;
3878 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupConnectionSettings( IDirectPlay4A *iface,
3879 DWORD flags, DPID group, DPLCONNECTION *connection )
3881 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3882 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
3883 return DP_OK;
3886 static HRESULT WINAPI IDirectPlay4Impl_SetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
3887 DPID group, DPLCONNECTION *connection )
3889 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3890 FIXME( "(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
3891 return DP_OK;
3894 static HRESULT WINAPI IDirectPlay4AImpl_StartSession( IDirectPlay4A *iface, DWORD flags,
3895 DPID group )
3897 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3898 return IDirectPlayX_StartSession( &This->IDirectPlay4_iface, flags, group );
3901 static HRESULT WINAPI IDirectPlay4Impl_StartSession( IDirectPlay4 *iface, DWORD flags, DPID group )
3903 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3904 FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, flags, group );
3905 return DP_OK;
3908 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupFlags( IDirectPlay4A *iface, DPID group,
3909 DWORD *flags )
3911 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3912 return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4_iface, group, flags );
3915 static HRESULT WINAPI IDirectPlay4Impl_GetGroupFlags( IDirectPlay4 *iface, DPID group,
3916 DWORD *flags )
3918 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3919 FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, flags );
3920 return DP_OK;
3923 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupParent( IDirectPlay4A *iface, DPID group,
3924 DPID *parent )
3926 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3927 return IDirectPlayX_GetGroupParent( &This->IDirectPlay4_iface, group, parent );
3930 static HRESULT WINAPI IDirectPlay4Impl_GetGroupParent( IDirectPlay4 *iface, DPID group,
3931 DPID *parent )
3933 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3934 lpGroupData gdata;
3936 TRACE( "(%p)->(0x%08x,%p)\n", This, group, parent );
3938 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
3939 return DPERR_INVALIDGROUP;
3941 *parent = gdata->dpid;
3943 return DP_OK;
3946 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAccount( IDirectPlay4A *iface, DPID player,
3947 DWORD flags, void *data, DWORD *size )
3949 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3950 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
3951 return DP_OK;
3954 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAccount( IDirectPlay4 *iface, DPID player,
3955 DWORD flags, void *data, DWORD *size )
3957 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3958 FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
3959 return DP_OK;
3962 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerFlags( IDirectPlay4A *iface, DPID player,
3963 DWORD *flags )
3965 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3966 return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4_iface, player, flags );
3969 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerFlags( IDirectPlay4 *iface, DPID player,
3970 DWORD *flags )
3972 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3973 FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, flags );
3974 return DP_OK;
3977 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupOwner( IDirectPlay4A *iface, DPID group,
3978 DPID *owner )
3980 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3981 return IDirectPlayX_GetGroupOwner( &This->IDirectPlay4_iface, group, owner );
3984 static HRESULT WINAPI IDirectPlay4Impl_GetGroupOwner( IDirectPlay4 *iface, DPID group,
3985 DPID *owner )
3987 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3988 FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, owner );
3989 return DP_OK;
3992 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupOwner( IDirectPlay4A *iface, DPID group,
3993 DPID owner )
3995 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3996 return IDirectPlayX_SetGroupOwner( &This->IDirectPlay4_iface, group, owner );
3999 static HRESULT WINAPI IDirectPlay4Impl_SetGroupOwner( IDirectPlay4 *iface, DPID group ,
4000 DPID owner )
4002 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4003 FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, owner );
4004 return DP_OK;
4007 static HRESULT WINAPI IDirectPlay4AImpl_SendEx( IDirectPlay4A *iface, DPID from, DPID to,
4008 DWORD flags, void *data, DWORD size, DWORD priority, DWORD timeout, void *context,
4009 DWORD *msgid )
4011 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4012 return IDirectPlayX_SendEx( &This->IDirectPlay4_iface, from, to, flags, data, size, priority,
4013 timeout, context, msgid );
4016 static HRESULT WINAPI IDirectPlay4Impl_SendEx( IDirectPlay4 *iface, DPID from, DPID to,
4017 DWORD flags, void *data, DWORD size, DWORD priority, DWORD timeout, void *context,
4018 DWORD *msgid )
4020 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4022 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p): semi-stub\n",
4023 This, from, to, flags, data, size, priority, timeout, context, msgid );
4025 if ( This->dp2->connectionInitialized == NO_PROVIDER )
4026 return DPERR_UNINITIALIZED;
4028 /* FIXME: Add parameter checking */
4029 /* FIXME: First call to this needs to acquire a message id which will be
4030 * used for multiple sends
4033 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4035 /* Verify that the message is being sent from a valid local player. The
4036 * from player may be anonymous DPID_UNKNOWN
4038 if ( from != DPID_UNKNOWN && !DP_FindPlayer( This, from ) )
4040 WARN( "INFO: Invalid from player 0x%08x\n", from );
4041 return DPERR_INVALIDPLAYER;
4044 /* Verify that the message is being sent to a valid player, group or to
4045 * everyone. If it's valid, send it to those players.
4047 if ( to == DPID_ALLPLAYERS )
4049 /* See if SP has the ability to multicast. If so, use it */
4050 if ( This->dp2->spData.lpCB->SendToGroupEx )
4051 FIXME( "Use group sendex to group 0\n" );
4052 else if ( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4053 FIXME( "Use obsolete group send to group 0\n" );
4054 else /* No multicast, multiplicate */
4055 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4057 else if ( DP_FindPlayer( This, to ) )
4059 /* Have the service provider send this message */
4060 /* FIXME: Could optimize for local interface sends */
4061 return DP_SP_SendEx( This, flags, data, size, priority, timeout, context, msgid );
4063 else if ( DP_FindAnyGroup( This, to ) )
4065 /* See if SP has the ability to multicast. If so, use it */
4066 if ( This->dp2->spData.lpCB->SendToGroupEx )
4067 FIXME( "Use group sendex\n" );
4068 else if ( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4069 FIXME( "Use obsolete group send to group\n" );
4070 else /* No multicast, multiplicate */
4071 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4074 else
4075 return DPERR_INVALIDPLAYER;
4077 /* FIXME: Should return what the send returned */
4078 return DP_OK;
4081 static HRESULT DP_SP_SendEx( IDirectPlayImpl *This, DWORD dwFlags, void *lpData, DWORD dwDataSize,
4082 DWORD dwPriority, DWORD dwTimeout, void *lpContext, DWORD *lpdwMsgID )
4084 LPDPMSG lpMElem;
4086 FIXME( ": stub\n" );
4088 /* FIXME: This queuing should only be for async messages */
4090 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4091 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4093 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4095 /* FIXME: Need to queue based on priority */
4096 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4098 return DP_OK;
4101 static HRESULT WINAPI IDirectPlay4AImpl_GetMessageQueue( IDirectPlay4A *iface, DPID from, DPID to,
4102 DWORD flags, DWORD *msgs, DWORD *bytes )
4104 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4105 return IDirectPlayX_GetMessageQueue( &This->IDirectPlay4_iface, from, to, flags, msgs, bytes );
4108 static HRESULT WINAPI IDirectPlay4Impl_GetMessageQueue( IDirectPlay4 *iface, DPID from, DPID to,
4109 DWORD flags, DWORD *msgs, DWORD *bytes )
4111 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4112 HRESULT hr = DP_OK;
4114 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p): semi-stub\n", This, from, to, flags, msgs, bytes );
4116 /* FIXME: Do we need to do from and to sanity checking here? */
4117 /* FIXME: What about sends which are not immediate? */
4119 if ( This->dp2->spData.lpCB->GetMessageQueue )
4121 DPSP_GETMESSAGEQUEUEDATA data;
4123 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4125 /* FIXME: None of this is documented :( */
4126 data.lpISP = This->dp2->spData.lpISP;
4127 data.dwFlags = flags;
4128 data.idFrom = from;
4129 data.idTo = to;
4130 data.lpdwNumMsgs = msgs;
4131 data.lpdwNumBytes = bytes;
4133 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4135 else
4136 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4138 return hr;
4141 static HRESULT dplay_cancelmsg ( IDirectPlayImpl* This, DWORD msgid, DWORD flags, DWORD minprio,
4142 DWORD maxprio )
4144 HRESULT hr = DP_OK;
4146 FIXME( "(%p)->(0x%08x,0x%08x): semi stub\n", This, msgid, flags );
4148 if ( This->dp2->spData.lpCB->Cancel )
4150 DPSP_CANCELDATA data;
4152 TRACE( "Calling SP Cancel\n" );
4154 /* FIXME: Undocumented callback */
4156 data.lpISP = This->dp2->spData.lpISP;
4157 data.dwFlags = flags;
4158 data.lprglpvSPMsgID = NULL;
4159 data.cSPMsgID = msgid;
4160 data.dwMinPriority = minprio;
4161 data.dwMaxPriority = maxprio;
4163 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4165 else
4166 FIXME( "SP doesn't implement Cancel\n" );
4168 return hr;
4171 static HRESULT WINAPI IDirectPlay4AImpl_CancelMessage( IDirectPlay4A *iface, DWORD msgid,
4172 DWORD flags )
4174 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4175 return IDirectPlayX_CancelMessage( &This->IDirectPlay4_iface, msgid, flags );
4178 static HRESULT WINAPI IDirectPlay4Impl_CancelMessage( IDirectPlay4 *iface, DWORD msgid,
4179 DWORD flags )
4181 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4183 if ( flags != 0 )
4184 return DPERR_INVALIDFLAGS;
4186 if ( msgid == 0 )
4187 flags |= DPCANCELSEND_ALL;
4189 return dplay_cancelmsg( This, msgid, flags, 0, 0 );
4192 static HRESULT WINAPI IDirectPlay4AImpl_CancelPriority( IDirectPlay4A *iface, DWORD minprio,
4193 DWORD maxprio, DWORD flags )
4195 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4196 return IDirectPlayX_CancelPriority( &This->IDirectPlay4_iface, minprio, maxprio, flags );
4199 static HRESULT WINAPI IDirectPlay4Impl_CancelPriority( IDirectPlay4 *iface, DWORD minprio,
4200 DWORD maxprio, DWORD flags )
4202 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4204 if ( flags != 0 )
4205 return DPERR_INVALIDFLAGS;
4207 return dplay_cancelmsg( This, 0, DPCANCELSEND_PRIORITY, minprio, maxprio );
4210 static const IDirectPlay2Vtbl dp2A_vt =
4212 IDirectPlay2AImpl_QueryInterface,
4213 IDirectPlay2AImpl_AddRef,
4214 IDirectPlay2AImpl_Release,
4215 IDirectPlay2AImpl_AddPlayerToGroup,
4216 IDirectPlay2AImpl_Close,
4217 IDirectPlay2AImpl_CreateGroup,
4218 IDirectPlay2AImpl_CreatePlayer,
4219 IDirectPlay2AImpl_DeletePlayerFromGroup,
4220 IDirectPlay2AImpl_DestroyGroup,
4221 IDirectPlay2AImpl_DestroyPlayer,
4222 IDirectPlay2AImpl_EnumGroupPlayers,
4223 IDirectPlay2AImpl_EnumGroups,
4224 IDirectPlay2AImpl_EnumPlayers,
4225 IDirectPlay2AImpl_EnumSessions,
4226 IDirectPlay2AImpl_GetCaps,
4227 IDirectPlay2AImpl_GetGroupData,
4228 IDirectPlay2AImpl_GetGroupName,
4229 IDirectPlay2AImpl_GetMessageCount,
4230 IDirectPlay2AImpl_GetPlayerAddress,
4231 IDirectPlay2AImpl_GetPlayerCaps,
4232 IDirectPlay2AImpl_GetPlayerData,
4233 IDirectPlay2AImpl_GetPlayerName,
4234 IDirectPlay2AImpl_GetSessionDesc,
4235 IDirectPlay2AImpl_Initialize,
4236 IDirectPlay2AImpl_Open,
4237 IDirectPlay2AImpl_Receive,
4238 IDirectPlay2AImpl_Send,
4239 IDirectPlay2AImpl_SetGroupData,
4240 IDirectPlay2AImpl_SetGroupName,
4241 IDirectPlay2AImpl_SetPlayerData,
4242 IDirectPlay2AImpl_SetPlayerName,
4243 IDirectPlay2AImpl_SetSessionDesc
4246 static const IDirectPlay4Vtbl dp4_vt =
4248 IDirectPlay4Impl_QueryInterface,
4249 IDirectPlay4Impl_AddRef,
4250 IDirectPlay4Impl_Release,
4251 IDirectPlay4Impl_AddPlayerToGroup,
4252 IDirectPlay4Impl_Close,
4253 IDirectPlay4Impl_CreateGroup,
4254 IDirectPlay4Impl_CreatePlayer,
4255 IDirectPlay4Impl_DeletePlayerFromGroup,
4256 IDirectPlay4Impl_DestroyGroup,
4257 IDirectPlay4Impl_DestroyPlayer,
4258 IDirectPlay4Impl_EnumGroupPlayers,
4259 IDirectPlay4Impl_EnumGroups,
4260 IDirectPlay4Impl_EnumPlayers,
4261 IDirectPlay4Impl_EnumSessions,
4262 IDirectPlay4Impl_GetCaps,
4263 IDirectPlay4Impl_GetGroupData,
4264 IDirectPlay4Impl_GetGroupName,
4265 IDirectPlay4Impl_GetMessageCount,
4266 IDirectPlay4Impl_GetPlayerAddress,
4267 IDirectPlay4Impl_GetPlayerCaps,
4268 IDirectPlay4Impl_GetPlayerData,
4269 IDirectPlay4Impl_GetPlayerName,
4270 IDirectPlay4Impl_GetSessionDesc,
4271 IDirectPlay4Impl_Initialize,
4272 IDirectPlay4Impl_Open,
4273 IDirectPlay4Impl_Receive,
4274 IDirectPlay4Impl_Send,
4275 IDirectPlay4Impl_SetGroupData,
4276 IDirectPlay4Impl_SetGroupName,
4277 IDirectPlay4Impl_SetPlayerData,
4278 IDirectPlay4Impl_SetPlayerName,
4279 IDirectPlay4Impl_SetSessionDesc,
4280 IDirectPlay4Impl_AddGroupToGroup,
4281 IDirectPlay4Impl_CreateGroupInGroup,
4282 IDirectPlay4Impl_DeleteGroupFromGroup,
4283 IDirectPlay4Impl_EnumConnections,
4284 IDirectPlay4Impl_EnumGroupsInGroup,
4285 IDirectPlay4Impl_GetGroupConnectionSettings,
4286 IDirectPlay4Impl_InitializeConnection,
4287 IDirectPlay4Impl_SecureOpen,
4288 IDirectPlay4Impl_SendChatMessage,
4289 IDirectPlay4Impl_SetGroupConnectionSettings,
4290 IDirectPlay4Impl_StartSession,
4291 IDirectPlay4Impl_GetGroupFlags,
4292 IDirectPlay4Impl_GetGroupParent,
4293 IDirectPlay4Impl_GetPlayerAccount,
4294 IDirectPlay4Impl_GetPlayerFlags,
4295 IDirectPlay4Impl_GetGroupOwner,
4296 IDirectPlay4Impl_SetGroupOwner,
4297 IDirectPlay4Impl_SendEx,
4298 IDirectPlay4Impl_GetMessageQueue,
4299 IDirectPlay4Impl_CancelMessage,
4300 IDirectPlay4Impl_CancelPriority
4303 static const IDirectPlay4Vtbl dp4A_vt =
4305 IDirectPlay4AImpl_QueryInterface,
4306 IDirectPlay4AImpl_AddRef,
4307 IDirectPlay4AImpl_Release,
4308 IDirectPlay4AImpl_AddPlayerToGroup,
4309 IDirectPlay4AImpl_Close,
4310 IDirectPlay4AImpl_CreateGroup,
4311 IDirectPlay4AImpl_CreatePlayer,
4312 IDirectPlay4AImpl_DeletePlayerFromGroup,
4313 IDirectPlay4AImpl_DestroyGroup,
4314 IDirectPlay4AImpl_DestroyPlayer,
4315 IDirectPlay4AImpl_EnumGroupPlayers,
4316 IDirectPlay4AImpl_EnumGroups,
4317 IDirectPlay4AImpl_EnumPlayers,
4318 IDirectPlay4AImpl_EnumSessions,
4319 IDirectPlay4AImpl_GetCaps,
4320 IDirectPlay4AImpl_GetGroupData,
4321 IDirectPlay4AImpl_GetGroupName,
4322 IDirectPlay4AImpl_GetMessageCount,
4323 IDirectPlay4AImpl_GetPlayerAddress,
4324 IDirectPlay4AImpl_GetPlayerCaps,
4325 IDirectPlay4AImpl_GetPlayerData,
4326 IDirectPlay4AImpl_GetPlayerName,
4327 IDirectPlay4AImpl_GetSessionDesc,
4328 IDirectPlay4AImpl_Initialize,
4329 IDirectPlay4AImpl_Open,
4330 IDirectPlay4AImpl_Receive,
4331 IDirectPlay4AImpl_Send,
4332 IDirectPlay4AImpl_SetGroupData,
4333 IDirectPlay4AImpl_SetGroupName,
4334 IDirectPlay4AImpl_SetPlayerData,
4335 IDirectPlay4AImpl_SetPlayerName,
4336 IDirectPlay4AImpl_SetSessionDesc,
4337 IDirectPlay4AImpl_AddGroupToGroup,
4338 IDirectPlay4AImpl_CreateGroupInGroup,
4339 IDirectPlay4AImpl_DeleteGroupFromGroup,
4340 IDirectPlay4AImpl_EnumConnections,
4341 IDirectPlay4AImpl_EnumGroupsInGroup,
4342 IDirectPlay4AImpl_GetGroupConnectionSettings,
4343 IDirectPlay4AImpl_InitializeConnection,
4344 IDirectPlay4AImpl_SecureOpen,
4345 IDirectPlay4AImpl_SendChatMessage,
4346 IDirectPlay4AImpl_SetGroupConnectionSettings,
4347 IDirectPlay4AImpl_StartSession,
4348 IDirectPlay4AImpl_GetGroupFlags,
4349 IDirectPlay4AImpl_GetGroupParent,
4350 IDirectPlay4AImpl_GetPlayerAccount,
4351 IDirectPlay4AImpl_GetPlayerFlags,
4352 IDirectPlay4AImpl_GetGroupOwner,
4353 IDirectPlay4AImpl_SetGroupOwner,
4354 IDirectPlay4AImpl_SendEx,
4355 IDirectPlay4AImpl_GetMessageQueue,
4356 IDirectPlay4AImpl_CancelMessage,
4357 IDirectPlay4AImpl_CancelPriority
4360 HRESULT dplay_create( REFIID riid, void **ppv )
4362 IDirectPlayImpl *obj;
4363 HRESULT hr;
4365 TRACE( "(%s, %p)\n", debugstr_guid( riid ), ppv );
4367 *ppv = NULL;
4368 obj = HeapAlloc( GetProcessHeap(), 0, sizeof( *obj ) );
4369 if ( !obj )
4370 return DPERR_OUTOFMEMORY;
4372 obj->IDirectPlay2A_iface.lpVtbl = &dp2A_vt;
4373 obj->IDirectPlay4A_iface.lpVtbl = &dp4A_vt;
4374 obj->IDirectPlay4_iface.lpVtbl = &dp4_vt;
4375 obj->numIfaces = 1;
4376 obj->ref2A = 0;
4377 obj->ref4A = 1;
4378 obj->ref4 = 0;
4380 InitializeCriticalSection( &obj->lock );
4381 obj->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlayImpl.lock");
4383 if ( DP_CreateDirectPlay2( obj ) )
4384 hr = IDirectPlayX_QueryInterface( &obj->IDirectPlay4A_iface, riid, ppv );
4385 else
4386 hr = DPERR_NOMEMORY;
4387 IDirectPlayX_Release( &obj->IDirectPlay4A_iface );
4389 return hr;
4393 HRESULT DP_GetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void **lplpData )
4395 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
4397 if( lpPlayer == NULL )
4399 return DPERR_INVALIDPLAYER;
4402 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
4404 return DP_OK;
4407 HRESULT DP_SetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void *lpData )
4409 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
4411 if( lpPlayer == NULL )
4413 return DPERR_INVALIDPLAYER;
4416 lpPlayer->lpPData->lpSPPlayerData = lpData;
4418 return DP_OK;
4421 /***************************************************************************
4422 * DirectPlayEnumerateAW
4424 * The pointer to the structure lpContext will be filled with the
4425 * appropriate data for each service offered by the OS. These services are
4426 * not necessarily available on this particular machine but are defined
4427 * as simple service providers under the "Service Providers" registry key.
4428 * This structure is then passed to lpEnumCallback for each of the different
4429 * services.
4431 * This API is useful only for applications written using DirectX3 or
4432 * worse. It is superseded by IDirectPlay3::EnumConnections which also
4433 * gives information on the actual connections.
4435 * defn of a service provider:
4436 * A dynamic-link library used by DirectPlay to communicate over a network.
4437 * The service provider contains all the network-specific code required
4438 * to send and receive messages. Online services and network operators can
4439 * supply service providers to use specialized hardware, protocols, communications
4440 * media, and network resources.
4443 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
4444 LPDPENUMDPCALLBACKW lpEnumCallbackW,
4445 LPVOID lpContext)
4447 HKEY hkResult;
4448 static const WCHAR searchSubKey[] = {
4449 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
4450 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
4451 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
4452 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
4453 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
4454 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
4456 DWORD dwIndex;
4457 FILETIME filetime;
4459 char *descriptionA = NULL;
4460 DWORD max_sizeOfDescriptionA = 0;
4461 WCHAR *descriptionW = NULL;
4462 DWORD max_sizeOfDescriptionW = 0;
4464 if (!lpEnumCallbackA && !lpEnumCallbackW)
4466 return DPERR_INVALIDPARAMS;
4469 /* Need to loop over the service providers in the registry */
4470 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
4471 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
4473 /* Hmmm. Does this mean that there are no service providers? */
4474 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
4475 return DPERR_GENERIC;
4478 /* Traverse all the service providers we have available */
4479 dwIndex = 0;
4480 while (1)
4482 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
4483 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
4484 HKEY hkServiceProvider;
4485 GUID serviceProviderGUID;
4486 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
4487 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
4488 LONG ret_value;
4490 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4491 NULL, NULL, NULL, &filetime);
4492 if (ret_value == ERROR_NO_MORE_ITEMS)
4493 break;
4494 else if (ret_value != ERROR_SUCCESS)
4496 ERR(": could not enumerate on service provider key.\n");
4497 return DPERR_EXCEPTION;
4499 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
4501 /* Open the key for this service provider */
4502 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
4504 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
4505 continue;
4508 /* Get the GUID from the registry */
4509 if (RegQueryValueExW(hkServiceProvider, guidKey,
4510 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
4512 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
4513 continue;
4515 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
4517 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
4518 continue;
4520 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
4522 /* The enumeration will return FALSE if we are not to continue.
4524 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
4525 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
4526 * I think that it simply means that they are in-line with DirectX 6.0
4528 if (lpEnumCallbackA)
4530 DWORD sizeOfDescription = 0;
4532 /* Note that this is the A case of this function, so use the A variant to get the description string */
4533 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
4534 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
4536 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
4537 continue;
4539 if (sizeOfDescription > max_sizeOfDescriptionA)
4541 HeapFree(GetProcessHeap(), 0, descriptionA);
4542 max_sizeOfDescriptionA = sizeOfDescription;
4544 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
4545 RegQueryValueExA(hkServiceProvider, "DescriptionA",
4546 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
4548 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
4549 goto end;
4551 else
4553 DWORD sizeOfDescription = 0;
4555 if (RegQueryValueExW(hkServiceProvider, descW,
4556 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
4558 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
4559 continue;
4561 if (sizeOfDescription > max_sizeOfDescriptionW)
4563 HeapFree(GetProcessHeap(), 0, descriptionW);
4564 max_sizeOfDescriptionW = sizeOfDescription;
4566 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
4567 RegQueryValueExW(hkServiceProvider, descW,
4568 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
4570 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
4571 goto end;
4574 dwIndex++;
4577 end:
4578 HeapFree(GetProcessHeap(), 0, descriptionA);
4579 HeapFree(GetProcessHeap(), 0, descriptionW);
4581 return DP_OK;
4584 /***************************************************************************
4585 * DirectPlayEnumerate [DPLAYX.9]
4586 * DirectPlayEnumerateA [DPLAYX.2]
4588 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
4590 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
4592 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
4595 /***************************************************************************
4596 * DirectPlayEnumerateW [DPLAYX.3]
4598 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
4600 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
4602 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
4605 typedef struct tagCreateEnum
4607 LPVOID lpConn;
4608 LPCGUID lpGuid;
4609 } CreateEnumData, *lpCreateEnumData;
4611 /* Find and copy the matching connection for the SP guid */
4612 static BOOL CALLBACK cbDPCreateEnumConnections(
4613 LPCGUID lpguidSP,
4614 LPVOID lpConnection,
4615 DWORD dwConnectionSize,
4616 LPCDPNAME lpName,
4617 DWORD dwFlags,
4618 LPVOID lpContext)
4620 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
4622 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
4624 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
4626 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4627 dwConnectionSize );
4628 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
4630 /* Found the record that we were looking for */
4631 return FALSE;
4634 /* Haven't found what were looking for yet */
4635 return TRUE;
4639 /***************************************************************************
4640 * DirectPlayCreate [DPLAYX.1]
4643 HRESULT WINAPI DirectPlayCreate
4644 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
4646 HRESULT hr;
4647 LPDIRECTPLAY3A lpDP3A;
4648 CreateEnumData cbData;
4650 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
4652 if( pUnk != NULL )
4654 return CLASS_E_NOAGGREGATION;
4657 if( (lplpDP == NULL) || (lpGUID == NULL) )
4659 return DPERR_INVALIDPARAMS;
4662 /* Create an IDirectPlay object. We don't support that so we'll cheat and
4663 give them an IDirectPlay2A object and hope that doesn't cause problems */
4664 if ( dplay_create( &IID_IDirectPlay2A, (void**)lplpDP ) != DP_OK )
4665 return DPERR_UNAVAILABLE;
4667 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
4669 /* The GUID_NULL means don't bind a service provider. Just return the
4670 interface as is */
4671 return DP_OK;
4674 /* Bind the desired service provider since lpGUID is non NULL */
4675 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
4677 /* We're going to use a DP3 interface */
4678 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
4679 (LPVOID*)&lpDP3A );
4680 if( FAILED(hr) )
4682 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
4683 return hr;
4686 cbData.lpConn = NULL;
4687 cbData.lpGuid = lpGUID;
4689 /* We were given a service provider, find info about it... */
4690 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
4691 &cbData, DPCONNECTION_DIRECTPLAY );
4692 if( ( FAILED(hr) ) ||
4693 ( cbData.lpConn == NULL )
4696 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
4697 IDirectPlayX_Release( lpDP3A );
4698 return DPERR_UNAVAILABLE;
4701 /* Initialize the service provider */
4702 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
4703 if( FAILED(hr) )
4705 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
4706 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
4707 IDirectPlayX_Release( lpDP3A );
4708 return hr;
4711 /* Release our version of the interface now that we're done with it */
4712 IDirectPlayX_Release( lpDP3A );
4713 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
4715 return DP_OK;