1 /* Direct Play 2,3,4 Implementation
3 * Copyright 1998,1999,2000,2001 - Peter Hunnisett
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
39 #include "dplayx_global.h"
40 #include "name_server.h"
41 #include "dplayx_queue.h"
42 #include "wine/dplaysp.h"
43 #include "dplay_global.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
47 /* FIXME: Should this be externed? */
48 extern HRESULT DPL_CreateCompoundAddress
49 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
50 LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
53 /* Local function prototypes */
54 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
55 static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
56 LPDPNAME lpName, DWORD dwFlags,
57 HANDLE hEvent, BOOL bAnsi );
58 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
59 static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
60 LPVOID lpData, DWORD dwDataSize );
62 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, const DPID *lpid,
63 const DPNAME *lpName, DWORD dwFlags,
64 DPID idParent, BOOL bAnsi );
65 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
66 LPVOID lpData, DWORD dwDataSize );
67 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
68 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
69 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
74 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
75 static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
76 LPCDPNAME lpName, DWORD dwFlags,
78 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
80 /* Helper methods for player/group interfaces */
81 static HRESULT DP_IF_CreatePlayer
82 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
83 LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
84 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
85 static HRESULT DP_IF_DestroyGroup
86 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
87 static HRESULT DP_IF_DestroyPlayer
88 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
89 static HRESULT DP_IF_GetGroupName
90 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
91 LPDWORD lpdwDataSize, BOOL bAnsi );
92 static HRESULT DP_IF_GetPlayerName
93 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
94 LPDWORD lpdwDataSize, BOOL bAnsi );
95 static HRESULT DP_IF_SetGroupName
96 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
97 DWORD dwFlags, BOOL bAnsi );
98 static HRESULT DP_IF_SetPlayerName
99 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
100 DWORD dwFlags, BOOL bAnsi );
101 static HRESULT DP_IF_CreateGroup
102 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
103 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
104 DWORD dwFlags, BOOL bAnsi );
105 static HRESULT DP_IF_CreateGroupInGroup
106 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
107 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
108 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
109 static HRESULT DP_SetSessionDesc
110 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
111 DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
112 static HRESULT DP_SecureOpen
113 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
114 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
116 static HRESULT DP_SendEx
117 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
118 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
119 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
120 static HRESULT DP_IF_Receive
121 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
122 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
123 static HRESULT DP_IF_GetMessageQueue
124 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
125 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
126 static HRESULT DP_SP_SendEx
127 ( IDirectPlay2Impl* This, DWORD dwFlags,
128 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
129 LPVOID lpContext, LPDWORD lpdwMsgID );
130 static HRESULT DP_IF_CancelMessage
131 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
132 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
133 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
134 LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
135 DWORD dwFlags, LPVOID lpContext );
136 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
137 LPDWORD lpdwBufSize );
141 static inline DPID DP_NextObjectId(void);
142 static DPID DP_GetRemoteNextObjectId(void);
144 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
145 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
146 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
149 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
150 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
151 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
158 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
159 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
160 we don't have to change much */
161 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
163 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
164 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
166 /* Strip out all dwFlags values for CREATEPLAYER msg */
167 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
169 static LONG kludgePlayerGroupId = 1000;
172 static inline IDirectPlayImpl *impl_from_IDirectPlay4A( IDirectPlay4A *iface )
174 return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4A_iface );
177 static inline IDirectPlayImpl *impl_from_IDirectPlay4( IDirectPlay4 *iface )
179 return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4_iface );
182 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
184 IDirectPlay2AImpl *This = lpDP;
186 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
187 if ( This->dp2 == NULL )
192 This->dp2->bConnectionOpen = FALSE;
194 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
195 This->dp2->dwEnumSessionLock = 0;
197 This->dp2->bHostInterface = FALSE;
199 DPQ_INIT(This->dp2->receiveMsgs);
200 DPQ_INIT(This->dp2->sendMsgs);
201 DPQ_INIT(This->dp2->repliesExpected);
203 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
205 /* FIXME: Memory leak */
209 /* Provide an initial session desc with nothing in it */
210 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
212 sizeof( *This->dp2->lpSessionDesc ) );
213 if( This->dp2->lpSessionDesc == NULL )
215 /* FIXME: Memory leak */
218 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
220 /* We are emulating a dp 6 implementation */
221 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
223 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
224 sizeof( *This->dp2->spData.lpCB ) );
225 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
226 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
228 /* This is the pointer to the service provider */
229 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
230 (LPVOID*)&This->dp2->spData.lpISP, This ) )
233 /* FIXME: Memory leak */
237 /* Setup lobby provider information */
238 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
239 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
240 sizeof( *This->dp2->dplspData.lpCB ) );
241 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
243 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
244 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
247 /* FIXME: Memory leak */
254 /* Definition of the global function in dplayx_queue.h. #
255 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
256 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
258 HeapFree( GetProcessHeap(), 0, elem );
261 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
263 IDirectPlay2AImpl *This = lpDP;
265 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
267 TerminateThread( This->dp2->hEnumSessionThread, 0 );
268 CloseHandle( This->dp2->hEnumSessionThread );
271 /* Finish with the SP - have it shutdown */
272 if( This->dp2->spData.lpCB->ShutdownEx )
274 DPSP_SHUTDOWNDATA data;
276 TRACE( "Calling SP ShutdownEx\n" );
278 data.lpISP = This->dp2->spData.lpISP;
280 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
282 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
284 TRACE( "Calling obsolete SP Shutdown\n" );
285 (*This->dp2->spData.lpCB->Shutdown)();
288 /* Unload the SP (if it exists) */
289 if( This->dp2->hServiceProvider != 0 )
291 FreeLibrary( This->dp2->hServiceProvider );
294 /* Unload the Lobby Provider (if it exists) */
295 if( This->dp2->hDPLobbyProvider != 0 )
297 FreeLibrary( This->dp2->hDPLobbyProvider );
300 /* FIXME: Need to delete receive and send msgs queue contents */
302 NS_DeleteSessionCache( This->dp2->lpNameServerData );
304 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
306 IDirectPlaySP_Release( This->dp2->spData.lpISP );
308 /* Delete the contents */
309 HeapFree( GetProcessHeap(), 0, This->dp2 );
314 static void dplay_destroy(IDirectPlayImpl *obj)
316 DP_DestroyDirectPlay2( obj );
317 obj->lock.DebugInfo->Spare[0] = 0;
318 DeleteCriticalSection( &obj->lock );
319 HeapFree( GetProcessHeap(), 0, obj );
322 static inline DPID DP_NextObjectId(void)
324 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
327 /* *lplpReply will be non NULL iff there is something to reply */
328 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
329 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
330 WORD wCommandId, WORD wVersion,
331 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
333 TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
334 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
339 /* Name server needs to handle this request */
340 case DPMSGCMD_ENUMSESSIONSREQUEST:
342 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
345 /* Name server needs to handle this request */
346 case DPMSGCMD_ENUMSESSIONSREPLY:
347 /* No reply expected */
348 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
349 This->dp2->spData.dwSPHeaderSize,
351 This->dp2->lpNameServerData );
354 case DPMSGCMD_REQUESTNEWPLAYERID:
356 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = lpcMessageBody;
358 LPDPMSG_NEWPLAYERIDREPLY lpReply;
360 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
362 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
364 FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
367 /* Setup the reply */
368 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
369 This->dp2->spData.dwSPHeaderSize );
371 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
372 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
373 lpReply->envelope.wVersion = DPMSGVER_DP6;
375 lpReply->dpidNewPlayerId = DP_NextObjectId();
377 TRACE( "Allocating new playerid 0x%08x from remote request\n",
378 lpReply->dpidNewPlayerId );
382 case DPMSGCMD_GETNAMETABLEREPLY:
383 case DPMSGCMD_NEWPLAYERIDREPLY:
385 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
388 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
392 case DPMSGCMD_JUSTENVELOPE:
393 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
394 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
395 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
398 case DPMSGCMD_FORWARDADDPLAYER:
403 TRACE( "Sending message to self to get my addr\n" );
404 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
408 case DPMSGCMD_FORWARDADDPLAYERNACK:
409 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
413 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
418 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
424 static HRESULT WINAPI IDirectPlay4AImpl_QueryInterface( IDirectPlay4A *iface, REFIID riid,
427 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
428 return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
431 static HRESULT WINAPI IDirectPlay4Impl_QueryInterface( IDirectPlay4 *iface, REFIID riid,
434 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
436 if ( IsEqualGUID( &IID_IUnknown, riid ) )
438 TRACE( "(%p)->(IID_IUnknown %p)\n", This, ppv );
439 *ppv = &This->IDirectPlay4A_iface;
441 else if ( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
443 TRACE( "(%p)->(IID_IDirectPlay2A %p)\n", This, ppv );
444 *ppv = &This->IDirectPlay4A_iface;
446 else if ( IsEqualGUID( &IID_IDirectPlay2, riid ) )
448 TRACE( "(%p)->(IID_IDirectPlay2 %p)\n", This, ppv );
449 *ppv = &This->IDirectPlay4_iface;
451 else if ( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
453 TRACE( "(%p)->(IID_IDirectPlay3A %p)\n", This, ppv );
454 *ppv = &This->IDirectPlay4A_iface;
456 else if ( IsEqualGUID( &IID_IDirectPlay3, riid ) )
458 TRACE( "(%p)->(IID_IDirectPlay3 %p)\n", This, ppv );
459 *ppv = &This->IDirectPlay4_iface;
461 else if ( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
463 TRACE( "(%p)->(IID_IDirectPlay4A %p)\n", This, ppv );
464 *ppv = &This->IDirectPlay4A_iface;
466 else if ( IsEqualGUID( &IID_IDirectPlay4, riid ) )
468 TRACE( "(%p)->(IID_IDirectPlay4 %p)\n", This, ppv );
469 *ppv = &This->IDirectPlay4_iface;
473 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
475 return E_NOINTERFACE;
478 IUnknown_AddRef((IUnknown*)*ppv);
482 static ULONG WINAPI IDirectPlay4AImpl_AddRef(IDirectPlay4A *iface)
484 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
485 ULONG ref = InterlockedIncrement( &This->ref4A );
487 TRACE( "(%p) ref4A=%d\n", This, ref );
490 InterlockedIncrement( &This->numIfaces );
495 static ULONG WINAPI IDirectPlay4Impl_AddRef(IDirectPlay4 *iface)
497 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
498 ULONG ref = InterlockedIncrement( &This->ref4 );
500 TRACE( "(%p) ref4=%d\n", This, ref );
503 InterlockedIncrement( &This->numIfaces );
508 static ULONG WINAPI IDirectPlay4AImpl_Release(IDirectPlay4A *iface)
510 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
511 ULONG ref = InterlockedDecrement( &This->ref4A );
513 TRACE( "(%p) ref4A=%d\n", This, ref );
515 if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
516 dplay_destroy( This );
521 static ULONG WINAPI IDirectPlay4Impl_Release(IDirectPlay4 *iface)
523 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
524 ULONG ref = InterlockedDecrement( &This->ref4 );
526 TRACE( "(%p) ref4=%d\n", This, ref );
528 if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
529 dplay_destroy( This );
534 static HRESULT WINAPI IDirectPlay4AImpl_AddPlayerToGroup( IDirectPlay4A *iface, DPID group,
537 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
538 return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
541 static HRESULT WINAPI IDirectPlay4Impl_AddPlayerToGroup( IDirectPlay4 *iface, DPID group,
544 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
547 lpPlayerList newplist;
549 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );
551 if ( This->dp2->connectionInitialized == NO_PROVIDER )
552 return DPERR_UNINITIALIZED;
555 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
556 return DPERR_INVALIDGROUP;
558 /* Find the player */
559 if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
560 return DPERR_INVALIDPLAYER;
562 /* Create a player list (ie "shortcut" ) */
563 newplist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *newplist ) );
565 return DPERR_CANTADDPLAYER;
567 /* Add the shortcut */
568 plist->lpPData->uRef++;
569 newplist->lpPData = plist->lpPData;
571 /* Add the player to the list of players for this group */
572 DPQ_INSERT(gdata->players, newplist, players);
574 /* Let the SP know that we've added a player to the group */
575 if ( This->dp2->spData.lpCB->AddPlayerToGroup )
577 DPSP_ADDPLAYERTOGROUPDATA data;
579 TRACE( "Calling SP AddPlayerToGroup\n" );
581 data.idPlayer = player;
582 data.idGroup = group;
583 data.lpISP = This->dp2->spData.lpISP;
585 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
588 /* Inform all other peers of the addition of player to the group. If there are
589 * no peers keep this event quiet.
590 * Also, if this event was the result of another machine sending it to us,
591 * don't bother rebroadcasting it.
593 if ( This->dp2->lpSessionDesc &&
594 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
596 DPMSG_ADDPLAYERTOGROUP msg;
597 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
599 msg.dpIdGroup = group;
600 msg.dpIdPlayer = player;
602 /* FIXME: Correct to just use send effectively? */
603 /* FIXME: Should size include data w/ message or just message "header" */
604 /* FIXME: Check return code */
605 IDirectPlayX_SendEx( iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
612 static HRESULT WINAPI IDirectPlay4AImpl_Close( IDirectPlay4A *iface )
614 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
615 return IDirectPlayX_Close( &This->IDirectPlay4_iface);
618 static HRESULT WINAPI IDirectPlay4Impl_Close( IDirectPlay4 *iface )
620 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
623 TRACE( "(%p)", This );
625 /* FIXME: Need to find a new host I assume (how?) */
626 /* FIXME: Need to destroy all local groups */
627 /* FIXME: Need to migrate all remotely visible players to the new host */
629 /* Invoke the SP callback to inform of session close */
630 if( This->dp2->spData.lpCB->CloseEx )
634 TRACE( "Calling SP CloseEx\n" );
635 data.lpISP = This->dp2->spData.lpISP;
636 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
638 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
640 TRACE( "Calling SP Close (obsolete interface)\n" );
641 hr = (*This->dp2->spData.lpCB->Close)();
648 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
649 const DPNAME *lpName, DWORD dwFlags,
650 DPID idParent, BOOL bAnsi )
654 /* Allocate the new space and add to end of high level group list */
655 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
657 if( lpGData == NULL )
662 DPQ_INIT(lpGData->groups);
663 DPQ_INIT(lpGData->players);
665 /* Set the desired player ID - no sanity checking to see if it exists */
666 lpGData->dpid = *lpid;
668 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
670 /* FIXME: Should we check that the parent exists? */
671 lpGData->parent = idParent;
673 /* FIXME: Should we validate the dwFlags? */
674 lpGData->dwFlags = dwFlags;
676 TRACE( "Created group id 0x%08x\n", *lpid );
681 /* This method assumes that all links to it are already deleted */
683 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
687 TRACE( "(%p)->(0x%08x)\n", This, dpid );
689 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
691 if( lpGList == NULL )
693 ERR( "DPID 0x%08x not found\n", dpid );
697 if( --(lpGList->lpGData->uRef) )
699 FIXME( "Why is this not the last reference to group?\n" );
704 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
705 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
707 /* Remove and Delete Player List object */
708 HeapFree( GetProcessHeap(), 0, lpGList );
712 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
714 lpGroupList lpGroups;
716 TRACE( "(%p)->(0x%08x)\n", This, dpid );
718 if( dpid == DPID_SYSTEM_GROUP )
720 return This->dp2->lpSysGroup;
724 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
727 if( lpGroups == NULL )
732 return lpGroups->lpGData;
735 static HRESULT DP_IF_CreateGroup
736 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
737 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
738 DWORD dwFlags, BOOL bAnsi )
742 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
743 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
746 if( This->dp2->connectionInitialized == NO_PROVIDER )
748 return DPERR_UNINITIALIZED;
751 /* If the name is not specified, we must provide one */
752 if( DPID_UNKNOWN == *lpidGroup )
754 /* If we are the name server, we decide on the group ids. If not, we
755 * must ask for one before attempting a creation.
757 if( This->dp2->bHostInterface )
759 *lpidGroup = DP_NextObjectId();
763 *lpidGroup = DP_GetRemoteNextObjectId();
767 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
768 DPID_NOPARENT_GROUP, bAnsi );
770 if( lpGData == NULL )
772 return DPERR_CANTADDPLAYER; /* yes player not group */
775 if( DPID_SYSTEM_GROUP == *lpidGroup )
777 This->dp2->lpSysGroup = lpGData;
778 TRACE( "Inserting system group\n" );
782 /* Insert into the system group */
783 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
784 lpGroup->lpGData = lpGData;
786 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
789 /* Something is now referencing this data */
792 /* Set all the important stuff for the group */
793 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
795 /* FIXME: We should only create the system group if GetCaps returns
796 * DPCAPS_GROUPOPTIMIZED.
799 /* Let the SP know that we've created this group */
800 if( This->dp2->spData.lpCB->CreateGroup )
802 DPSP_CREATEGROUPDATA data;
803 DWORD dwCreateFlags = 0;
805 TRACE( "Calling SP CreateGroup\n" );
807 if( *lpidGroup == DPID_NOPARENT_GROUP )
808 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
810 if( lpMsgHdr == NULL )
811 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
813 if( dwFlags & DPGROUP_HIDDEN )
814 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
816 data.idGroup = *lpidGroup;
817 data.dwFlags = dwCreateFlags;
818 data.lpSPMessageHeader = lpMsgHdr;
819 data.lpISP = This->dp2->spData.lpISP;
821 (*This->dp2->spData.lpCB->CreateGroup)( &data );
824 /* Inform all other peers of the creation of a new group. If there are
825 * no peers keep this event quiet.
826 * Also if this message was sent to us, don't rebroadcast.
828 if( ( lpMsgHdr == NULL ) &&
829 This->dp2->lpSessionDesc &&
830 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
832 DPMSG_CREATEPLAYERORGROUP msg;
833 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
835 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
836 msg.dpId = *lpidGroup;
837 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
839 msg.dwDataSize = dwDataSize;
840 msg.dpnName = *lpGroupName;
841 msg.dpIdParent = DPID_NOPARENT_GROUP;
842 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
844 /* FIXME: Correct to just use send effectively? */
845 /* FIXME: Should size include data w/ message or just message "header" */
846 /* FIXME: Check return code */
847 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
848 0, 0, NULL, NULL, bAnsi );
854 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroup( IDirectPlay4A *iface, DPID *lpidGroup,
855 DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
857 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
859 *lpidGroup = DPID_UNKNOWN;
861 return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
865 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
866 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
867 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
869 *lpidGroup = DPID_UNKNOWN;
871 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
872 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
877 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
878 LPVOID lpData, DWORD dwDataSize )
880 /* Clear out the data with this player */
881 if( dwFlags & DPSET_LOCAL )
883 if ( lpGData->dwLocalDataSize != 0 )
885 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
886 lpGData->lpLocalData = NULL;
887 lpGData->dwLocalDataSize = 0;
892 if( lpGData->dwRemoteDataSize != 0 )
894 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
895 lpGData->lpRemoteData = NULL;
896 lpGData->dwRemoteDataSize = 0;
900 /* Reallocate for new data */
903 if( dwFlags & DPSET_LOCAL )
905 lpGData->lpLocalData = lpData;
906 lpGData->dwLocalDataSize = dwDataSize;
910 lpGData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
911 CopyMemory( lpGData->lpRemoteData, lpData, dwDataSize );
912 lpGData->dwRemoteDataSize = dwDataSize;
918 /* This function will just create the storage for the new player. */
920 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
921 LPDPNAME lpName, DWORD dwFlags,
922 HANDLE hEvent, BOOL bAnsi )
924 lpPlayerData lpPData;
926 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
928 /* Allocate the storage for the player and associate it with list element */
929 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
930 if( lpPData == NULL )
935 /* Set the desired player ID */
936 lpPData->dpid = *lpid;
938 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
940 lpPData->dwFlags = dwFlags;
942 /* If we were given an event handle, duplicate it */
945 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
946 GetCurrentProcess(), &lpPData->hEvent,
947 0, FALSE, DUPLICATE_SAME_ACCESS )
950 /* FIXME: Memory leak */
951 ERR( "Can't duplicate player msg handle %p\n", hEvent );
955 /* Initialize the SP data section */
956 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
958 TRACE( "Created player id 0x%08x\n", *lpid );
960 if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
961 This->dp2->lpSessionDesc->dwCurrentPlayers++;
966 /* Delete the contents of the DPNAME struct */
968 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
970 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
971 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
974 /* This method assumes that all links to it are already deleted */
976 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
978 lpPlayerList lpPList;
980 TRACE( "(%p)->(0x%08x)\n", This, dpid );
982 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
984 if( lpPList == NULL )
986 ERR( "DPID 0x%08x not found\n", dpid );
990 /* Verify that this is the last reference to the data */
991 if( --(lpPList->lpPData->uRef) )
993 FIXME( "Why is this not the last reference to player?\n" );
998 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1000 CloseHandle( lpPList->lpPData->hEvent );
1001 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1003 /* Delete Player List object */
1004 HeapFree( GetProcessHeap(), 0, lpPList );
1007 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1009 lpPlayerList lpPlayers;
1011 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1013 if(This->dp2->lpSysGroup == NULL)
1016 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1021 /* Basic area for Dst must already be allocated */
1022 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1026 ZeroMemory( lpDst, sizeof( *lpDst ) );
1027 lpDst->dwSize = sizeof( *lpDst );
1031 if( lpSrc->dwSize != sizeof( *lpSrc) )
1036 /* Delete any existing pointers */
1037 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1038 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1040 /* Copy as required */
1041 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1045 if( lpSrc->u1.lpszShortNameA )
1047 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1048 strlen(lpSrc->u1.lpszShortNameA)+1 );
1049 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1051 if( lpSrc->u2.lpszLongNameA )
1053 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1054 strlen(lpSrc->u2.lpszLongNameA)+1 );
1055 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1060 if( lpSrc->u1.lpszShortNameA )
1062 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1063 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1064 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1066 if( lpSrc->u2.lpszLongNameA )
1068 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1069 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1070 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1078 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1079 LPVOID lpData, DWORD dwDataSize )
1081 /* Clear out the data with this player */
1082 if( dwFlags & DPSET_LOCAL )
1084 if ( lpPData->dwLocalDataSize != 0 )
1086 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1087 lpPData->lpLocalData = NULL;
1088 lpPData->dwLocalDataSize = 0;
1093 if( lpPData->dwRemoteDataSize != 0 )
1095 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1096 lpPData->lpRemoteData = NULL;
1097 lpPData->dwRemoteDataSize = 0;
1101 /* Reallocate for new data */
1102 if( lpData != NULL )
1105 if( dwFlags & DPSET_LOCAL )
1107 lpPData->lpLocalData = lpData;
1108 lpPData->dwLocalDataSize = dwDataSize;
1112 lpPData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
1113 CopyMemory( lpPData->lpRemoteData, lpData, dwDataSize );
1114 lpPData->dwRemoteDataSize = dwDataSize;
1120 static HRESULT DP_IF_CreatePlayer
1121 ( IDirectPlay2Impl* This,
1122 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1124 LPDPNAME lpPlayerName,
1132 lpPlayerData lpPData;
1133 lpPlayerList lpPList;
1134 DWORD dwCreateFlags = 0;
1136 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1137 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1138 dwDataSize, dwFlags, bAnsi );
1139 if( This->dp2->connectionInitialized == NO_PROVIDER )
1141 return DPERR_UNINITIALIZED;
1146 dwFlags = DPPLAYER_SPECTATOR;
1149 if( lpidPlayer == NULL )
1151 return DPERR_INVALIDPARAMS;
1155 /* Determine the creation flags for the player. These will be passed
1156 * to the name server if requesting a player id and to the SP when
1157 * informing it of the player creation
1160 if( dwFlags & DPPLAYER_SERVERPLAYER )
1162 if( *lpidPlayer == DPID_SERVERPLAYER )
1164 /* Server player for the host interface */
1165 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1167 else if( *lpidPlayer == DPID_NAME_SERVER )
1169 /* Name server - master of everything */
1170 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1174 /* Server player for a non host interface */
1175 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1179 if( lpMsgHdr == NULL )
1180 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1183 /* Verify we know how to handle all the flags */
1184 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1185 ( dwFlags & DPPLAYER_SPECTATOR )
1189 /* Assume non fatal failure */
1190 ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1193 /* If the name is not specified, we must provide one */
1194 if( *lpidPlayer == DPID_UNKNOWN )
1196 /* If we are the session master, we dish out the group/player ids */
1197 if( This->dp2->bHostInterface )
1199 *lpidPlayer = DP_NextObjectId();
1203 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1207 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1214 /* FIXME: Would be nice to perhaps verify that we don't already have
1219 /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
1221 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1224 if( lpPData == NULL )
1226 return DPERR_CANTADDPLAYER;
1229 /* Create the list object and link it in */
1230 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1231 if( lpPList == NULL )
1233 FIXME( "Memory leak\n" );
1234 return DPERR_CANTADDPLAYER;
1238 lpPList->lpPData = lpPData;
1240 /* Add the player to the system group */
1241 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1243 /* Update the information and send it to all players in the session */
1244 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1246 /* Let the SP know that we've created this player */
1247 if( This->dp2->spData.lpCB->CreatePlayer )
1249 DPSP_CREATEPLAYERDATA data;
1251 data.idPlayer = *lpidPlayer;
1252 data.dwFlags = dwCreateFlags;
1253 data.lpSPMessageHeader = lpMsgHdr;
1254 data.lpISP = This->dp2->spData.lpISP;
1256 TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1257 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1259 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1264 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1268 /* Now let the SP know that this player is a member of the system group */
1269 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1271 DPSP_ADDPLAYERTOGROUPDATA data;
1273 data.idPlayer = *lpidPlayer;
1274 data.idGroup = DPID_SYSTEM_GROUP;
1275 data.lpISP = This->dp2->spData.lpISP;
1277 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1279 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1284 ERR( "Failed to add player to sys group with sp: %s\n",
1285 DPLAYX_HresultToString(hr) );
1290 if( This->dp2->bHostInterface == FALSE )
1292 /* Let the name server know about the creation of this player */
1293 /* FIXME: Is this only to be done for the creation of a server player or
1294 * is this used for regular players? If only for server players, move
1295 * this call to DP_SecureOpen(...);
1298 TRACE( "Sending message to self to get my addr\n" );
1299 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1302 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1305 /* Inform all other peers of the creation of a new player. If there are
1306 * no peers keep this quiet.
1307 * Also, if this was a remote event, no need to rebroadcast it.
1309 if( ( lpMsgHdr == NULL ) &&
1310 This->dp2->lpSessionDesc &&
1311 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1313 DPMSG_CREATEPLAYERORGROUP msg;
1314 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1316 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1317 msg.dpId = *lpidPlayer;
1318 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1319 msg.lpData = lpData;
1320 msg.dwDataSize = dwDataSize;
1321 msg.dpnName = *lpPlayerName;
1322 msg.dpIdParent = DPID_NOPARENT_GROUP;
1323 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1325 /* FIXME: Correct to just use send effectively? */
1326 /* FIXME: Should size include data w/ message or just message "header" */
1327 /* FIXME: Check return code */
1328 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1329 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1336 static HRESULT WINAPI IDirectPlay4AImpl_CreatePlayer( IDirectPlay4A *iface, DPID *lpidPlayer,
1337 DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1339 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1341 if( lpidPlayer == NULL )
1343 return DPERR_INVALIDPARAMS;
1346 if( dwFlags & DPPLAYER_SERVERPLAYER )
1348 *lpidPlayer = DPID_SERVERPLAYER;
1352 *lpidPlayer = DPID_UNKNOWN;
1355 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1356 lpData, dwDataSize, dwFlags, TRUE );
1359 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1360 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1361 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1363 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1365 if( lpidPlayer == NULL )
1367 return DPERR_INVALIDPARAMS;
1370 if( dwFlags & DPPLAYER_SERVERPLAYER )
1372 *lpidPlayer = DPID_SERVERPLAYER;
1376 *lpidPlayer = DPID_UNKNOWN;
1379 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1380 lpData, dwDataSize, dwFlags, FALSE );
1383 static DPID DP_GetRemoteNextObjectId(void)
1388 return DP_NextObjectId();
1391 static HRESULT WINAPI IDirectPlay4AImpl_DeletePlayerFromGroup( IDirectPlay4A *iface, DPID group,
1394 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1395 return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1398 static HRESULT WINAPI IDirectPlay4Impl_DeletePlayerFromGroup( IDirectPlay4 *iface, DPID group,
1401 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1407 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );
1409 /* Find the group */
1410 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
1411 return DPERR_INVALIDGROUP;
1413 /* Find the player */
1414 if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
1415 return DPERR_INVALIDPLAYER;
1417 /* Remove the player shortcut from the group */
1418 DPQ_REMOVE_ENTRY( gdata->players, players, lpPData->dpid, ==, player, plist );
1421 return DPERR_INVALIDPLAYER;
1423 /* One less reference */
1424 plist->lpPData->uRef--;
1426 /* Delete the Player List element */
1427 HeapFree( GetProcessHeap(), 0, plist );
1429 /* Inform the SP if they care */
1430 if ( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1432 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1434 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1435 data.idPlayer = player;
1436 data.idGroup = group;
1437 data.lpISP = This->dp2->spData.lpISP;
1438 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1441 /* Need to send a DELETEPLAYERFROMGROUP message */
1442 FIXME( "Need to send a message\n" );
1447 typedef struct _DPRGOPContext
1449 IDirectPlay3Impl* This;
1452 } DPRGOPContext, *lpDPRGOPContext;
1454 static BOOL CALLBACK
1455 cbRemoveGroupOrPlayer(
1462 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1464 TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1465 dpId, dwPlayerType, lpCtxt->idGroup );
1467 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1469 if ( FAILED( IDirectPlayX_DeleteGroupFromGroup( &lpCtxt->This->IDirectPlay4_iface,
1470 lpCtxt->idGroup, dpId ) ) )
1471 ERR( "Unable to delete group 0x%08x from group 0x%08x\n", dpId, lpCtxt->idGroup );
1473 else if ( FAILED( IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface,
1474 lpCtxt->idGroup, dpId ) ) )
1475 ERR( "Unable to delete player 0x%08x from grp 0x%08x\n", dpId, lpCtxt->idGroup );
1477 return TRUE; /* Continue enumeration */
1480 static HRESULT DP_IF_DestroyGroup
1481 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1483 lpGroupData lpGData;
1484 DPRGOPContext context;
1486 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1487 This, lpMsgHdr, idGroup, bAnsi );
1489 /* Find the group */
1490 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1492 return DPERR_INVALIDPLAYER; /* yes player */
1495 context.This = (IDirectPlay3Impl*)This;
1496 context.bAnsi = bAnsi;
1497 context.idGroup = idGroup;
1499 /* Remove all players that this group has */
1500 IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, idGroup, NULL, cbRemoveGroupOrPlayer,
1503 /* Remove all links to groups that this group has since this is dp3 */
1504 IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, idGroup, NULL, cbRemoveGroupOrPlayer,
1505 (void*)&context, 0 );
1507 /* Remove this group from the parent group - if it has one */
1508 if( ( idGroup != DPID_SYSTEM_GROUP ) && ( lpGData->parent != DPID_SYSTEM_GROUP ) )
1509 IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, lpGData->parent, idGroup );
1511 /* Now delete this group data and list from the system group */
1512 DP_DeleteGroup( This, idGroup );
1514 /* Let the SP know that we've destroyed this group */
1515 if( This->dp2->spData.lpCB->DeleteGroup )
1517 DPSP_DELETEGROUPDATA data;
1519 FIXME( "data.dwFlags is incorrect\n" );
1521 data.idGroup = idGroup;
1523 data.lpISP = This->dp2->spData.lpISP;
1525 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1528 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1533 static HRESULT WINAPI IDirectPlay4AImpl_DestroyGroup( IDirectPlay4A *iface, DPID idGroup )
1535 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1536 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1539 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1540 ( LPDIRECTPLAY2 iface, DPID idGroup )
1542 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1543 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1546 typedef struct _DPFAGContext
1548 IDirectPlay2Impl* This;
1551 } DPFAGContext, *lpDPFAGContext;
1553 static HRESULT DP_IF_DestroyPlayer
1554 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1556 DPFAGContext cbContext;
1558 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1559 This, lpMsgHdr, idPlayer, bAnsi );
1561 if( This->dp2->connectionInitialized == NO_PROVIDER )
1563 return DPERR_UNINITIALIZED;
1566 if( DP_FindPlayer( This, idPlayer ) == NULL )
1568 return DPERR_INVALIDPLAYER;
1571 /* FIXME: If the player is remote, we must be the host to delete this */
1573 cbContext.This = This;
1574 cbContext.idPlayer = idPlayer;
1575 cbContext.bAnsi = bAnsi;
1577 /* Find each group and call DeletePlayerFromGroup if the player is a
1578 member of the group */
1579 IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, NULL, cbDeletePlayerFromAllGroups, &cbContext,
1582 /* Now delete player and player list from the sys group */
1583 DP_DeletePlayer( This, idPlayer );
1585 /* Let the SP know that we've destroyed this group */
1586 if( This->dp2->spData.lpCB->DeletePlayer )
1588 DPSP_DELETEPLAYERDATA data;
1590 FIXME( "data.dwFlags is incorrect\n" );
1592 data.idPlayer = idPlayer;
1594 data.lpISP = This->dp2->spData.lpISP;
1596 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1599 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1604 static BOOL CALLBACK
1605 cbDeletePlayerFromAllGroups(
1612 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1614 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1616 IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, lpCtxt->idPlayer );
1618 /* Enumerate all groups in this group since this will normally only
1619 * be called for top level groups
1621 IDirectPlayX_EnumGroupsInGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, NULL,
1622 cbDeletePlayerFromAllGroups, lpContext, DPENUMGROUPS_ALL);
1627 ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
1633 static HRESULT WINAPI IDirectPlay4AImpl_DestroyPlayer( IDirectPlay4A *iface, DPID idPlayer )
1635 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1636 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1639 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1640 ( LPDIRECTPLAY2 iface, DPID idPlayer )
1642 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1643 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1646 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupPlayers( IDirectPlay4A *iface, DPID group,
1647 GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1649 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1650 return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance, enumplayercb,
1654 static HRESULT WINAPI IDirectPlay4Impl_EnumGroupPlayers( IDirectPlay4 *iface, DPID group,
1655 GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1657 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1661 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
1664 if ( This->dp2->connectionInitialized == NO_PROVIDER )
1665 return DPERR_UNINITIALIZED;
1667 /* Find the group */
1668 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
1669 return DPERR_INVALIDGROUP;
1671 if ( DPQ_IS_EMPTY( gdata->players ) )
1674 /* Walk the players in this group */
1675 for( plist = DPQ_FIRST( gdata->players ); ; plist = DPQ_NEXT( plist->players ) )
1677 /* We do not enum the name server or app server as they are of no
1678 * consequence to the end user.
1680 if ( ( plist->lpPData->dpid != DPID_NAME_SERVER ) &&
1681 ( plist->lpPData->dpid != DPID_SERVERPLAYER ) )
1683 /* FIXME: Need to add stuff for flags checking */
1684 if ( !enumplayercb( plist->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1685 &plist->lpPData->name, plist->lpPData->dwFlags, context ) )
1686 /* User requested break */
1690 if ( DPQ_IS_ENDOFLIST( plist->players ) )
1696 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
1697 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroups( IDirectPlay4A *iface, GUID *instance,
1698 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1700 return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1704 static HRESULT WINAPI IDirectPlay4Impl_EnumGroups ( IDirectPlay4 *iface, GUID *instance,
1705 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1707 return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1711 static HRESULT WINAPI IDirectPlay4AImpl_EnumPlayers( IDirectPlay4A *iface, GUID *instance,
1712 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1714 return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1718 static HRESULT WINAPI IDirectPlay4Impl_EnumPlayers( IDirectPlay4 *iface, GUID *instance,
1719 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1721 return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1725 /* This function should call the registered callback function that the user
1726 passed into EnumSessions for each entry available.
1728 static void DP_InvokeEnumSessionCallbacks
1729 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
1734 LPDPSESSIONDESC2 lpSessionDesc;
1736 FIXME( ": not checking for conditions\n" );
1738 /* Not sure if this should be pruning but it's convenient */
1739 NS_PruneSessionCache( lpNSInfo );
1741 NS_ResetSessionEnumeration( lpNSInfo );
1743 /* Enumerate all sessions */
1744 /* FIXME: Need to indicate ANSI */
1745 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
1747 TRACE( "EnumSessionsCallback2 invoked\n" );
1748 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
1754 /* Invoke one last time to indicate that there is no more to come */
1755 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
1758 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
1760 EnumSessionAsyncCallbackData* data = lpContext;
1761 HANDLE hSuicideRequest = data->hSuicideRequest;
1762 DWORD dwTimeout = data->dwTimeout;
1764 TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
1770 /* Sleep up to dwTimeout waiting for request to terminate thread */
1771 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
1773 TRACE( "Thread terminating on terminate request\n" );
1777 /* Now resend the enum request */
1778 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
1779 data->dwEnumSessionFlags,
1784 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
1785 /* FIXME: Should we kill this thread? How to inform the main thread? */
1790 TRACE( "Thread terminating\n" );
1792 /* Clean up the thread data */
1793 CloseHandle( hSuicideRequest );
1794 HeapFree( GetProcessHeap(), 0, lpContext );
1796 /* FIXME: Need to have some notification to main app thread that this is
1797 * dead. It would serve two purposes. 1) allow sync on termination
1798 * so that we don't actually send something to ourselves when we
1799 * become name server (race condition) and 2) so that if we die
1800 * abnormally something else will be able to tell.
1806 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
1808 /* Does a thread exist? If so we were doing an async enum session */
1809 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
1811 TRACE( "Killing EnumSession thread %p\n",
1812 This->dp2->hEnumSessionThread );
1814 /* Request that the thread kill itself nicely */
1815 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
1816 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
1818 /* We no longer need to know about the thread */
1819 CloseHandle( This->dp2->hEnumSessionThread );
1821 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
1825 static HRESULT WINAPI IDirectPlay4AImpl_EnumSessions( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
1826 DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
1828 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1829 return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
1833 static HRESULT WINAPI IDirectPlay4Impl_EnumSessions( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
1834 DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
1836 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1841 TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x)\n", This, sdesc, timeout, enumsessioncb,
1844 if ( This->dp2->connectionInitialized == NO_PROVIDER )
1845 return DPERR_UNINITIALIZED;
1847 /* Can't enumerate if the interface is already open */
1848 if ( This->dp2->bConnectionOpen )
1849 return DPERR_GENERIC;
1851 /* The loading of a lobby provider _seems_ to require a backdoor loading
1852 * of the service provider to also associate with this DP object. This is
1853 * because the app doesn't seem to have to call EnumConnections and
1854 * InitializeConnection for the SP before calling this method. As such
1855 * we'll do their dirty work for them with a quick hack so as to always
1856 * load the TCP/IP service provider.
1858 * The correct solution would seem to involve creating a dialog box which
1859 * contains the possible SPs. These dialog boxes most likely follow SDK
1862 if ( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
1864 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
1866 if ( !DP_BuildSPCompoundAddr( (GUID*)&DPSPGUID_TCPIP, &connection, &size ) )
1868 ERR( "Can't build compound addr\n" );
1869 return DPERR_GENERIC;
1872 hr = IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, 0 );
1876 HeapFree( GetProcessHeap(), 0, connection );
1877 This->dp2->bSPInitialized = TRUE;
1881 /* Use the service provider default? */
1885 caps.dwSize = sizeof( caps );
1887 IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, &caps, 0 );
1888 timeout = caps.dwTimeout;
1890 timeout = DPMSG_WAIT_5_SECS; /* Provide the TCP/IP default */
1893 if ( flags & DPENUMSESSIONS_STOPASYNC )
1895 DP_KillEnumSessionThread( This );
1899 if ( flags & DPENUMSESSIONS_ASYNC )
1901 /* Enumerate everything presently in the local session cache */
1902 DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
1905 if ( This->dp2->dwEnumSessionLock )
1906 return DPERR_CONNECTING;
1908 /* See if we've already created a thread to service this interface */
1909 if ( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
1912 This->dp2->dwEnumSessionLock++;
1914 /* Send the first enum request inline since the user may cancel a dialog
1915 * if one is presented. Also, may also have a connecting return code.
1917 hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags,
1918 &This->dp2->spData );
1920 if ( SUCCEEDED(hr) )
1922 EnumSessionAsyncCallbackData* data = HeapAlloc( GetProcessHeap(),
1923 HEAP_ZERO_MEMORY, sizeof( *data ) );
1924 /* FIXME: need to kill the thread on object deletion */
1925 data->lpSpData = &This->dp2->spData;
1926 data->requestGuid = sdesc->guidApplication;
1927 data->dwEnumSessionFlags = flags;
1928 data->dwTimeout = timeout;
1930 This->dp2->hKillEnumSessionThreadEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1931 if ( !DuplicateHandle( GetCurrentProcess(), This->dp2->hKillEnumSessionThreadEvent,
1932 GetCurrentProcess(), &data->hSuicideRequest, 0, FALSE,
1933 DUPLICATE_SAME_ACCESS ) )
1934 ERR( "Can't duplicate thread killing handle\n" );
1936 TRACE( ": creating EnumSessionsRequest thread\n" );
1937 This->dp2->hEnumSessionThread = CreateThread( NULL, 0,
1938 DP_EnumSessionsSendAsyncRequestThread, data, 0, &tid );
1940 This->dp2->dwEnumSessionLock--;
1945 /* Invalidate the session cache for the interface */
1946 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
1947 /* Send the broadcast for session enumeration */
1948 hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags, &This->dp2->spData );
1949 SleepEx( timeout, FALSE );
1950 DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
1957 static HRESULT WINAPI IDirectPlay4AImpl_GetCaps( IDirectPlay4A *iface, DPCAPS *caps, DWORD flags )
1959 return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
1962 static HRESULT WINAPI IDirectPlay4Impl_GetCaps( IDirectPlay4 *iface, DPCAPS *caps, DWORD flags )
1964 return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
1967 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupData( IDirectPlay4A *iface, DPID group,
1968 void *data, DWORD *size, DWORD flags )
1970 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1971 return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
1974 static HRESULT WINAPI IDirectPlay4Impl_GetGroupData( IDirectPlay4 *iface, DPID group,
1975 void *data, DWORD *size, DWORD flags )
1977 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1982 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, group, data, size, flags );
1984 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
1985 return DPERR_INVALIDGROUP;
1987 /* How much buffer is required? */
1988 if ( flags & DPSET_LOCAL )
1990 bufsize = gdata->dwLocalDataSize;
1991 src = gdata->lpLocalData;
1995 bufsize = gdata->dwRemoteDataSize;
1996 src = gdata->lpRemoteData;
1999 /* Is the user requesting to know how big a buffer is required? */
2000 if ( !data || *size < bufsize )
2003 return DPERR_BUFFERTOOSMALL;
2006 CopyMemory( data, src, bufsize );
2011 static HRESULT DP_IF_GetGroupName
2012 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2013 LPDWORD lpdwDataSize, BOOL bAnsi )
2015 lpGroupData lpGData;
2016 LPDPNAME lpName = lpData;
2017 DWORD dwRequiredDataSize;
2019 FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2020 This, idGroup, lpData, lpdwDataSize, bAnsi );
2022 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2024 return DPERR_INVALIDGROUP;
2027 dwRequiredDataSize = lpGData->name.dwSize;
2029 if( lpGData->name.u1.lpszShortNameA )
2031 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2034 if( lpGData->name.u2.lpszLongNameA )
2036 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2039 if( ( lpData == NULL ) ||
2040 ( *lpdwDataSize < dwRequiredDataSize )
2043 *lpdwDataSize = dwRequiredDataSize;
2044 return DPERR_BUFFERTOOSMALL;
2047 /* Copy the structure */
2048 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2050 if( lpGData->name.u1.lpszShortNameA )
2052 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2053 lpGData->name.u1.lpszShortNameA );
2057 lpName->u1.lpszShortNameA = NULL;
2060 if( lpGData->name.u1.lpszShortNameA )
2062 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2063 lpGData->name.u2.lpszLongNameA );
2067 lpName->u2.lpszLongNameA = NULL;
2073 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupName( IDirectPlay4A *iface, DPID idGroup,
2074 void *lpData, DWORD *lpdwDataSize )
2076 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2077 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2080 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2081 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2082 LPDWORD lpdwDataSize )
2084 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2085 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2088 static HRESULT WINAPI IDirectPlay4AImpl_GetMessageCount( IDirectPlay4A *iface, DPID player,
2091 return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2094 static HRESULT WINAPI IDirectPlay4Impl_GetMessageCount( IDirectPlay4 *iface, DPID player,
2097 return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2100 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAddress( IDirectPlay4A *iface, DPID player,
2101 void *data, DWORD *size )
2103 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2104 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2108 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAddress( IDirectPlay4 *iface, DPID player,
2109 void *data, DWORD *size )
2111 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2112 FIXME( "(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2116 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerCaps( IDirectPlay4A *iface, DPID player,
2117 DPCAPS *caps, DWORD flags )
2119 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2120 return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2123 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerCaps( IDirectPlay4 *iface, DPID player,
2124 DPCAPS *caps, DWORD flags )
2126 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2127 DPSP_GETCAPSDATA data;
2129 TRACE( "(%p)->(0x%08x,%p,0x%08x)\n", This, player, caps, flags);
2131 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2132 return DPERR_UNINITIALIZED;
2134 /* Query the service provider */
2135 data.idPlayer = player;
2136 data.dwFlags = flags;
2138 data.lpISP = This->dp2->spData.lpISP;
2140 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2143 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerData( IDirectPlay4A *iface, DPID player,
2144 void *data, DWORD *size, DWORD flags )
2146 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2147 return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2150 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerData( IDirectPlay4 *iface, DPID player,
2151 void *data, DWORD *size, DWORD flags )
2153 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2158 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, player, data, size, flags );
2160 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2161 return DPERR_UNINITIALIZED;
2163 if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
2164 return DPERR_INVALIDPLAYER;
2166 if ( flags & DPSET_LOCAL )
2168 bufsize = plist->lpPData->dwLocalDataSize;
2169 src = plist->lpPData->lpLocalData;
2173 bufsize = plist->lpPData->dwRemoteDataSize;
2174 src = plist->lpPData->lpRemoteData;
2177 /* Is the user requesting to know how big a buffer is required? */
2178 if ( !data || *size < bufsize )
2181 return DPERR_BUFFERTOOSMALL;
2184 CopyMemory( data, src, bufsize );
2189 static HRESULT DP_IF_GetPlayerName
2190 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2191 LPDWORD lpdwDataSize, BOOL bAnsi )
2193 lpPlayerList lpPList;
2194 LPDPNAME lpName = lpData;
2195 DWORD dwRequiredDataSize;
2197 FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2198 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2200 if( This->dp2->connectionInitialized == NO_PROVIDER )
2202 return DPERR_UNINITIALIZED;
2205 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2207 return DPERR_INVALIDPLAYER;
2210 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2212 if( lpPList->lpPData->name.u1.lpszShortNameA )
2214 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2217 if( lpPList->lpPData->name.u2.lpszLongNameA )
2219 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2222 if( ( lpData == NULL ) ||
2223 ( *lpdwDataSize < dwRequiredDataSize )
2226 *lpdwDataSize = dwRequiredDataSize;
2227 return DPERR_BUFFERTOOSMALL;
2230 /* Copy the structure */
2231 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2233 if( lpPList->lpPData->name.u1.lpszShortNameA )
2235 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2236 lpPList->lpPData->name.u1.lpszShortNameA );
2240 lpName->u1.lpszShortNameA = NULL;
2243 if( lpPList->lpPData->name.u1.lpszShortNameA )
2245 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2246 lpPList->lpPData->name.u2.lpszLongNameA );
2250 lpName->u2.lpszLongNameA = NULL;
2256 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
2257 void *lpData, DWORD *lpdwDataSize )
2259 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2260 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2263 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2264 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2265 LPDWORD lpdwDataSize )
2267 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2268 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2271 static HRESULT DP_GetSessionDesc
2272 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2275 DWORD dwRequiredSize;
2277 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2279 if( This->dp2->connectionInitialized == NO_PROVIDER )
2281 return DPERR_UNINITIALIZED;
2284 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2286 return DPERR_INVALIDPARAMS;
2289 /* FIXME: Get from This->dp2->lpSessionDesc */
2290 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2292 if ( ( lpData == NULL ) ||
2293 ( *lpdwDataSize < dwRequiredSize )
2296 *lpdwDataSize = dwRequiredSize;
2297 return DPERR_BUFFERTOOSMALL;
2300 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2305 static HRESULT WINAPI IDirectPlay4AImpl_GetSessionDesc( IDirectPlay4A *iface, void *lpData,
2306 DWORD *lpdwDataSize )
2308 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2309 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2312 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2313 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2315 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2316 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2319 /* Intended only for COM compatibility. Always returns an error. */
2320 static HRESULT WINAPI IDirectPlay4AImpl_Initialize( IDirectPlay4A *iface, GUID *guid )
2322 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2323 TRACE("(%p)->(%p): no-op\n", This, guid );
2324 return DPERR_ALREADYINITIALIZED;
2327 static HRESULT WINAPI IDirectPlay4Impl_Initialize( IDirectPlay4 *iface, GUID *guid )
2329 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2330 TRACE( "(%p)->(%p): no-op\n", This, guid );
2331 return DPERR_ALREADYINITIALIZED;
2335 static HRESULT DP_SecureOpen
2336 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2337 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2342 FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2343 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2345 if( This->dp2->connectionInitialized == NO_PROVIDER )
2347 return DPERR_UNINITIALIZED;
2350 if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
2352 TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
2353 return DPERR_INVALIDPARAMS;
2356 if( This->dp2->bConnectionOpen )
2358 TRACE( ": rejecting already open connection.\n" );
2359 return DPERR_ALREADYINITIALIZED;
2362 /* If we're enumerating, kill the thread */
2363 DP_KillEnumSessionThread( This );
2365 if( dwFlags & DPOPEN_CREATE )
2367 /* Rightoo - this computer is the host and the local computer needs to be
2368 the name server so that others can join this session */
2369 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2371 This->dp2->bHostInterface = TRUE;
2373 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2376 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2381 /* Invoke the conditional callback for the service provider */
2382 if( This->dp2->spData.lpCB->Open )
2386 FIXME( "Not all data fields are correct. Need new parameter\n" );
2388 data.bCreate = (dwFlags & DPOPEN_CREATE ) != 0;
2389 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2390 : NS_GetNSAddr( This->dp2->lpNameServerData );
2391 data.lpISP = This->dp2->spData.lpISP;
2392 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) != 0;
2393 data.dwOpenFlags = dwFlags;
2394 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2396 hr = (*This->dp2->spData.lpCB->Open)(&data);
2399 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2405 /* Create the system group of which everything is a part of */
2406 DPID systemGroup = DPID_SYSTEM_GROUP;
2408 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2413 if( dwFlags & DPOPEN_JOIN )
2415 DPID dpidServerId = DPID_UNKNOWN;
2417 /* Create the server player for this interface. This way we can receive
2418 * messages for this session.
2420 /* FIXME: I suppose that we should be setting an event for a receive
2421 * type of thing. That way the messaging thread could know to wake
2422 * up. DPlay would then trigger the hEvent for the player the
2423 * message is directed to.
2425 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2427 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2430 else if( dwFlags & DPOPEN_CREATE )
2432 DPID dpidNameServerId = DPID_NAME_SERVER;
2434 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2435 0, DPPLAYER_SERVERPLAYER, bAnsi );
2440 ERR( "Couldn't create name server/system player: %s\n",
2441 DPLAYX_HresultToString(hr) );
2447 static HRESULT WINAPI IDirectPlay4AImpl_Open( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
2450 return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
2453 static HRESULT WINAPI IDirectPlay4Impl_Open( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
2456 return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
2459 static HRESULT DP_IF_Receive
2460 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2461 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2463 LPDPMSG lpMsg = NULL;
2465 FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
2466 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2468 if( This->dp2->connectionInitialized == NO_PROVIDER )
2470 return DPERR_UNINITIALIZED;
2475 dwFlags = DPRECEIVE_ALL;
2478 /* If the lpData is NULL, we must be peeking the message */
2479 if( ( lpData == NULL ) &&
2480 !( dwFlags & DPRECEIVE_PEEK )
2483 return DPERR_INVALIDPARAMS;
2486 if( dwFlags & DPRECEIVE_ALL )
2488 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2490 if( !( dwFlags & DPRECEIVE_PEEK ) )
2492 FIXME( "Remove from queue\n" );
2495 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2496 ( dwFlags & DPRECEIVE_FROMPLAYER )
2499 FIXME( "Find matching message 0x%08x\n", dwFlags );
2503 ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
2508 return DPERR_NOMESSAGES;
2511 /* Copy into the provided buffer */
2512 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
2517 static HRESULT WINAPI IDirectPlay4AImpl_Receive( IDirectPlay4A *iface, DPID *lpidFrom,
2518 DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
2520 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2521 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, TRUE );
2524 static HRESULT WINAPI DirectPlay2WImpl_Receive
2525 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
2526 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2528 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2529 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2530 lpData, lpdwDataSize, FALSE );
2533 static HRESULT WINAPI IDirectPlay4AImpl_Send( IDirectPlay4A *iface, DPID from, DPID to,
2534 DWORD flags, void *data, DWORD size )
2536 return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
2539 static HRESULT WINAPI IDirectPlay4Impl_Send( IDirectPlay4 *iface, DPID from, DPID to,
2540 DWORD flags, void *data, DWORD size )
2542 return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
2545 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupData( IDirectPlay4A *iface, DPID group, void *data,
2546 DWORD size, DWORD flags )
2548 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2549 return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2552 static HRESULT WINAPI IDirectPlay4Impl_SetGroupData( IDirectPlay4 *iface, DPID group, void *data,
2553 DWORD size, DWORD flags )
2555 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2558 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, group, data, size, flags );
2560 /* Parameter check */
2561 if ( !data && size )
2562 return DPERR_INVALIDPARAMS;
2564 /* Find the pointer to the data for this player */
2565 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
2566 return DPERR_INVALIDOBJECT;
2568 if ( !(flags & DPSET_LOCAL) )
2570 FIXME( "Was this group created by this interface?\n" );
2571 /* FIXME: If this is a remote update need to allow it but not
2576 DP_SetGroupData( gdata, flags, data, size );
2578 /* FIXME: Only send a message if this group is local to the session otherwise
2579 * it will have been rejected above
2581 if ( !(flags & DPSET_LOCAL) )
2582 FIXME( "Send msg?\n" );
2587 static HRESULT DP_IF_SetGroupName
2588 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
2589 DWORD dwFlags, BOOL bAnsi )
2591 lpGroupData lpGData;
2593 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
2594 lpGroupName, dwFlags, bAnsi );
2596 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2598 return DPERR_INVALIDGROUP;
2601 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
2603 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
2604 FIXME( "Message not sent and dwFlags ignored\n" );
2609 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupName( IDirectPlay4A *iface, DPID idGroup,
2610 DPNAME *lpGroupName, DWORD dwFlags )
2612 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2613 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
2616 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
2617 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
2620 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2621 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
2624 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerData( IDirectPlay4A *iface, DPID player,
2625 void *data, DWORD size, DWORD flags )
2627 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2628 return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2631 static HRESULT WINAPI IDirectPlay4Impl_SetPlayerData( IDirectPlay4 *iface, DPID player,
2632 void *data, DWORD size, DWORD flags )
2634 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2637 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, player, data, size, flags );
2639 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2640 return DPERR_UNINITIALIZED;
2642 /* Parameter check */
2643 if ( !data && size )
2644 return DPERR_INVALIDPARAMS;
2646 /* Find the pointer to the data for this player */
2647 if ( (plist = DP_FindPlayer( This, player )) == NULL )
2648 return DPERR_INVALIDPLAYER;
2650 if ( !(flags & DPSET_LOCAL) )
2652 FIXME( "Was this group created by this interface?\n" );
2653 /* FIXME: If this is a remote update need to allow it but not
2658 DP_SetPlayerData( plist->lpPData, flags, data, size );
2660 if ( !(flags & DPSET_LOCAL) )
2661 FIXME( "Send msg?\n" );
2666 static HRESULT DP_IF_SetPlayerName
2667 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
2668 DWORD dwFlags, BOOL bAnsi )
2670 lpPlayerList lpPList;
2672 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
2673 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
2675 if( This->dp2->connectionInitialized == NO_PROVIDER )
2677 return DPERR_UNINITIALIZED;
2680 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2682 return DPERR_INVALIDGROUP;
2685 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
2687 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
2688 FIXME( "Message not sent and dwFlags ignored\n" );
2693 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
2694 DPNAME *lpPlayerName, DWORD dwFlags )
2696 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2697 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
2700 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
2701 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
2704 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2705 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
2708 static HRESULT DP_SetSessionDesc
2709 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
2710 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
2712 DWORD dwRequiredSize;
2713 LPDPSESSIONDESC2 lpTempSessDesc;
2715 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
2716 This, lpSessDesc, dwFlags, bInitial, bAnsi );
2718 if( This->dp2->connectionInitialized == NO_PROVIDER )
2720 return DPERR_UNINITIALIZED;
2725 return DPERR_INVALIDPARAMS;
2728 /* Only the host is allowed to update the session desc */
2729 if( !This->dp2->bHostInterface )
2731 return DPERR_ACCESSDENIED;
2734 /* FIXME: Copy into This->dp2->lpSessionDesc */
2735 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
2736 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
2738 if( lpTempSessDesc == NULL )
2740 return DPERR_OUTOFMEMORY;
2744 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
2746 This->dp2->lpSessionDesc = lpTempSessDesc;
2748 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
2751 /*Initializing session GUID*/
2752 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
2754 /* If this is an external invocation of the interface, we should be
2755 * letting everyone know that things have changed. Otherwise this is
2756 * just an initialization and it doesn't need to be propagated.
2760 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
2766 static HRESULT WINAPI IDirectPlay4AImpl_SetSessionDesc( IDirectPlay4A *iface,
2767 DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
2769 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2770 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
2773 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
2774 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
2776 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2777 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
2780 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
2781 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
2785 if( lpSessDesc == NULL )
2787 /* Hmmm..don't need any size? */
2788 ERR( "NULL lpSessDesc\n" );
2792 dwSize += sizeof( *lpSessDesc );
2796 if( lpSessDesc->u1.lpszSessionNameA )
2798 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
2801 if( lpSessDesc->u2.lpszPasswordA )
2803 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
2808 if( lpSessDesc->u1.lpszSessionName )
2810 dwSize += sizeof( WCHAR ) *
2811 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
2814 if( lpSessDesc->u2.lpszPassword )
2816 dwSize += sizeof( WCHAR ) *
2817 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
2824 /* Assumes that contiguous buffers are already allocated. */
2825 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
2826 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
2828 BYTE* lpStartOfFreeSpace;
2830 if( lpSessionDest == NULL )
2832 ERR( "NULL lpSessionDest\n" );
2836 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
2838 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
2842 if( lpSessionSrc->u1.lpszSessionNameA )
2844 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
2845 lpSessionDest->u1.lpszSessionNameA );
2846 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
2847 lpStartOfFreeSpace +=
2848 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
2851 if( lpSessionSrc->u2.lpszPasswordA )
2853 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
2854 lpSessionDest->u2.lpszPasswordA );
2855 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
2860 if( lpSessionSrc->u1.lpszSessionName )
2862 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
2863 lpSessionDest->u1.lpszSessionName );
2864 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
2865 lpStartOfFreeSpace += sizeof(WCHAR) *
2866 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
2869 if( lpSessionSrc->u2.lpszPassword )
2871 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
2872 lpSessionDest->u2.lpszPassword );
2873 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
2878 static HRESULT WINAPI IDirectPlay4AImpl_AddGroupToGroup( IDirectPlay4A *iface, DPID parent,
2881 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2882 return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
2885 static HRESULT WINAPI IDirectPlay4Impl_AddGroupToGroup( IDirectPlay4 *iface, DPID parent,
2888 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2892 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, parent, group );
2894 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2895 return DPERR_UNINITIALIZED;
2897 if ( !DP_FindAnyGroup(This, parent ) )
2898 return DPERR_INVALIDGROUP;
2900 if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
2901 return DPERR_INVALIDGROUP;
2903 /* Create a player list (ie "shortcut" ) */
2904 glist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *glist ) );
2906 return DPERR_CANTADDPLAYER;
2908 /* Add the shortcut */
2910 glist->lpGData = gdata;
2912 /* Add the player to the list of players for this group */
2913 DPQ_INSERT( gdata->groups, glist, groups );
2915 /* Send a ADDGROUPTOGROUP message */
2916 FIXME( "Not sending message\n" );
2921 static HRESULT DP_IF_CreateGroupInGroup
2922 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
2923 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
2924 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
2926 lpGroupData lpGParentData;
2927 lpGroupList lpGList;
2928 lpGroupData lpGData;
2930 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
2931 This, idParentGroup, lpidGroup, lpGroupName, lpData,
2932 dwDataSize, dwFlags, bAnsi );
2934 if( This->dp2->connectionInitialized == NO_PROVIDER )
2936 return DPERR_UNINITIALIZED;
2939 /* Verify that the specified parent is valid */
2940 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
2941 idParentGroup ) ) == NULL
2944 return DPERR_INVALIDGROUP;
2947 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
2948 dwFlags, idParentGroup, bAnsi );
2950 if( lpGData == NULL )
2952 return DPERR_CANTADDPLAYER; /* yes player not group */
2955 /* Something else is referencing this data */
2958 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
2960 /* The list has now been inserted into the interface group list. We now
2961 need to put a "shortcut" to this group in the parent group */
2962 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
2963 if( lpGList == NULL )
2965 FIXME( "Memory leak\n" );
2966 return DPERR_CANTADDPLAYER; /* yes player not group */
2969 lpGList->lpGData = lpGData;
2971 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
2973 /* Let the SP know that we've created this group */
2974 if( This->dp2->spData.lpCB->CreateGroup )
2976 DPSP_CREATEGROUPDATA data;
2978 TRACE( "Calling SP CreateGroup\n" );
2980 data.idGroup = *lpidGroup;
2981 data.dwFlags = dwFlags;
2982 data.lpSPMessageHeader = lpMsgHdr;
2983 data.lpISP = This->dp2->spData.lpISP;
2985 (*This->dp2->spData.lpCB->CreateGroup)( &data );
2988 /* Inform all other peers of the creation of a new group. If there are
2989 * no peers keep this quiet.
2991 if( This->dp2->lpSessionDesc &&
2992 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
2994 DPMSG_CREATEPLAYERORGROUP msg;
2996 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
2997 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
2998 msg.dpId = *lpidGroup;
2999 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3000 msg.lpData = lpData;
3001 msg.dwDataSize = dwDataSize;
3002 msg.dpnName = *lpGroupName;
3004 /* FIXME: Correct to just use send effectively? */
3005 /* FIXME: Should size include data w/ message or just message "header" */
3006 /* FIXME: Check return code */
3007 DP_SendEx( (IDirectPlay2Impl*)This,
3008 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3009 0, 0, NULL, NULL, bAnsi );
3015 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroupInGroup( IDirectPlay4A *iface,
3016 DPID idParentGroup, DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize,
3019 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3021 *lpidGroup = DPID_UNKNOWN;
3023 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
3024 dwDataSize, dwFlags, TRUE );
3027 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3028 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3029 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3032 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3034 *lpidGroup = DPID_UNKNOWN;
3036 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3037 lpGroupName, lpData, dwDataSize,
3041 static HRESULT WINAPI IDirectPlay4AImpl_DeleteGroupFromGroup( IDirectPlay4A *iface, DPID parent,
3044 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3045 return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
3048 static HRESULT WINAPI IDirectPlay4Impl_DeleteGroupFromGroup( IDirectPlay4 *iface, DPID parent,
3051 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3053 lpGroupData parentdata;
3055 TRACE("(%p)->(0x%08x,0x%08x)\n", This, parent, group );
3057 /* Is the parent group valid? */
3058 if ( ( parentdata = DP_FindAnyGroup(This, parent ) ) == NULL )
3059 return DPERR_INVALIDGROUP;
3061 /* Remove the group from the parent group queue */
3062 DPQ_REMOVE_ENTRY( parentdata->groups, groups, lpGData->dpid, ==, group, glist );
3064 if ( glist == NULL )
3065 return DPERR_INVALIDGROUP;
3067 /* Decrement the ref count */
3068 glist->lpGData->uRef--;
3070 /* Free up the list item */
3071 HeapFree( GetProcessHeap(), 0, glist );
3073 /* Should send a DELETEGROUPFROMGROUP message */
3074 FIXME( "message not sent\n" );
3079 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3080 LPDWORD lpdwBufSize )
3082 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3085 dpCompoundAddress.dwDataSize = sizeof( GUID );
3086 dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3087 dpCompoundAddress.lpData = lpcSpGuid;
3089 *lplpAddrBuf = NULL;
3092 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3093 lpdwBufSize, TRUE );
3095 if( hr != DPERR_BUFFERTOOSMALL )
3097 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3101 /* Now allocate the buffer */
3102 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3105 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3106 lpdwBufSize, TRUE );
3109 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3116 static HRESULT WINAPI IDirectPlay4AImpl_EnumConnections( IDirectPlay4A *iface,
3117 const GUID *lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, void *lpContext,
3120 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3121 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3123 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3126 dwFlags = DPCONNECTION_DIRECTPLAY;
3129 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3130 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3133 return DPERR_INVALIDFLAGS;
3136 if( !lpEnumCallback )
3138 return DPERR_INVALIDPARAMS;
3141 /* Enumerate DirectPlay service providers */
3142 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3145 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3146 LPCSTR guidDataSubKey = "Guid";
3147 char subKeyName[51];
3148 DWORD dwIndex, sizeOfSubKeyName=50;
3151 /* Need to loop over the service providers in the registry */
3152 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3153 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3155 /* Hmmm. Does this mean that there are no service providers? */
3156 ERR(": no service providers?\n");
3161 /* Traverse all the service providers we have available */
3163 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3164 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3165 ++dwIndex, sizeOfSubKeyName=51 )
3168 HKEY hkServiceProvider;
3169 GUID serviceProviderGUID;
3170 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3171 char returnBuffer[51];
3176 LPVOID lpAddressBuffer = NULL;
3177 DWORD dwAddressBufferSize = 0;
3179 TRACE(" this time through: %s\n", subKeyName );
3181 /* Get a handle for this particular service provider */
3182 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3183 &hkServiceProvider ) != ERROR_SUCCESS )
3185 ERR(": what the heck is going on?\n" );
3189 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3190 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3191 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3193 ERR(": missing GUID registry data members\n" );
3194 RegCloseKey(hkServiceProvider);
3197 RegCloseKey(hkServiceProvider);
3199 /* FIXME: Check return types to ensure we're interpreting data right */
3200 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3201 CLSIDFromString( buff, &serviceProviderGUID );
3202 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3204 /* Fill in the DPNAME struct for the service provider */
3205 dpName.dwSize = sizeof( dpName );
3207 dpName.u1.lpszShortNameA = subKeyName;
3208 dpName.u2.lpszLongNameA = NULL;
3210 /* Create the compound address for the service provider.
3211 * NOTE: This is a gruesome architectural scar right now. DP
3212 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3213 * native dll just gets around this little bit by allocating an
3214 * 80 byte buffer which isn't even filled with a valid compound
3215 * address. Oh well. Creating a proper compound address is the
3216 * way to go anyways despite this method taking slightly more
3217 * heap space and realtime :) */
3219 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3221 &dwAddressBufferSize );
3224 ERR( "Can't build compound addr\n" );
3225 return DPERR_GENERIC;
3228 /* The enumeration will return FALSE if we are not to continue */
3229 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3230 &dpName, dwFlags, lpContext ) )
3237 /* Enumerate DirectPlayLobby service providers */
3238 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3241 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3242 LPCSTR guidDataSubKey = "Guid";
3243 char subKeyName[51];
3244 DWORD dwIndex, sizeOfSubKeyName=50;
3247 /* Need to loop over the service providers in the registry */
3248 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3249 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3251 /* Hmmm. Does this mean that there are no service providers? */
3252 ERR(": no service providers?\n");
3257 /* Traverse all the lobby providers we have available */
3259 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3260 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3261 ++dwIndex, sizeOfSubKeyName=51 )
3264 HKEY hkServiceProvider;
3265 GUID serviceProviderGUID;
3266 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3267 char returnBuffer[51];
3272 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3273 LPVOID lpAddressBuffer = NULL;
3274 DWORD dwAddressBufferSize = 0;
3276 TRACE(" this time through: %s\n", subKeyName );
3278 /* Get a handle for this particular service provider */
3279 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3280 &hkServiceProvider ) != ERROR_SUCCESS )
3282 ERR(": what the heck is going on?\n" );
3286 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3287 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3288 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3290 ERR(": missing GUID registry data members\n" );
3291 RegCloseKey(hkServiceProvider);
3294 RegCloseKey(hkServiceProvider);
3296 /* FIXME: Check return types to ensure we're interpreting data right */
3297 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3298 CLSIDFromString( buff, &serviceProviderGUID );
3299 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3301 /* Fill in the DPNAME struct for the service provider */
3302 dpName.dwSize = sizeof( dpName );
3304 dpName.u1.lpszShortNameA = subKeyName;
3305 dpName.u2.lpszLongNameA = NULL;
3307 /* Create the compound address for the service provider.
3308 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3309 nast stuff. This may be why the native dll just gets around this little bit by
3310 allocating an 80 byte buffer which isn't even a filled with a valid compound
3311 address. Oh well. Creating a proper compound address is the way to go anyways
3312 despite this method taking slightly more heap space and realtime :) */
3314 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3315 dpCompoundAddress.dwDataSize = sizeof( GUID );
3316 dpCompoundAddress.lpData = &serviceProviderGUID;
3318 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3319 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3321 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3325 /* Now allocate the buffer */
3326 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3328 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3329 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3331 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3332 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3336 /* The enumeration will return FALSE if we are not to continue */
3337 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3338 &dpName, dwFlags, lpContext ) )
3340 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3343 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3350 static HRESULT WINAPI IDirectPlay4Impl_EnumConnections( IDirectPlay4 *iface,
3351 const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
3353 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3354 FIXME( "(%p)->(%p,%p,%p,0x%08x): stub\n", This, application, enumcb, context, flags );
3358 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupsInGroup( IDirectPlay4A *iface, DPID group,
3359 GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
3361 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3362 return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, group, instance,
3363 enumplayercb, context, flags );
3366 static HRESULT WINAPI IDirectPlay4Impl_EnumGroupsInGroup( IDirectPlay4 *iface, DPID group,
3367 GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
3369 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3373 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
3376 if ( This->dp2->connectionInitialized == NO_PROVIDER )
3377 return DPERR_UNINITIALIZED;
3379 if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
3380 return DPERR_INVALIDGROUP;
3382 if ( DPQ_IS_EMPTY( gdata->groups ) )
3386 for( glist = DPQ_FIRST( gdata->groups ); ; glist = DPQ_NEXT( glist->groups ) )
3388 /* FIXME: Should check flags for match here */
3389 if ( !(*enumplayercb)( glist->lpGData->dpid, DPPLAYERTYPE_GROUP, &glist->lpGData->name,
3391 return DP_OK; /* User requested break */
3393 if ( DPQ_IS_ENDOFLIST( glist->groups ) )
3400 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupConnectionSettings( IDirectPlay4A *iface,
3401 DWORD flags, DPID group, void *data, DWORD *size )
3403 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3404 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
3408 static HRESULT WINAPI IDirectPlay4Impl_GetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
3409 DPID group, void *data, DWORD *size )
3411 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3412 FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
3416 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
3417 REFGUID guidDataType,
3422 /* Looking for the GUID of the provider to load */
3423 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
3424 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
3427 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
3428 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
3430 if( dwDataSize != sizeof( GUID ) )
3432 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
3435 memcpy( lpContext, lpData, dwDataSize );
3437 /* There shouldn't be more than 1 GUID/compound address */
3441 /* Still waiting for what we want */
3446 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
3447 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
3450 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3451 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3452 LPCSTR guidDataSubKey = "Guid";
3453 LPCSTR majVerDataSubKey = "dwReserved1";
3454 LPCSTR minVerDataSubKey = "dwReserved2";
3455 LPCSTR pathSubKey = "Path";
3457 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
3459 /* FIXME: Cloned code with a quick hack. */
3460 for( i=0; i<2; i++ )
3463 LPCSTR searchSubKey;
3464 char subKeyName[51];
3465 DWORD dwIndex, sizeOfSubKeyName=50;
3468 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
3469 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
3472 /* Need to loop over the service providers in the registry */
3473 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3474 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3476 /* Hmmm. Does this mean that there are no service providers? */
3477 ERR(": no service providers?\n");
3481 /* Traverse all the service providers we have available */
3483 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3484 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3485 ++dwIndex, sizeOfSubKeyName=51 )
3488 HKEY hkServiceProvider;
3489 GUID serviceProviderGUID;
3490 DWORD returnType, sizeOfReturnBuffer = 255;
3491 char returnBuffer[256];
3495 TRACE(" this time through: %s\n", subKeyName );
3497 /* Get a handle for this particular service provider */
3498 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3499 &hkServiceProvider ) != ERROR_SUCCESS )
3501 ERR(": what the heck is going on?\n" );
3505 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3506 NULL, &returnType, (LPBYTE)returnBuffer,
3507 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3509 ERR(": missing GUID registry data members\n" );
3513 /* FIXME: Check return types to ensure we're interpreting data right */
3514 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3515 CLSIDFromString( buff, &serviceProviderGUID );
3516 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3518 /* Determine if this is the Service Provider that the user asked for */
3519 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
3524 if( i == 0 ) /* DP SP */
3526 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
3527 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
3528 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
3531 sizeOfReturnBuffer = 255;
3533 /* Get dwReserved1 */
3534 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
3535 NULL, &returnType, (LPBYTE)returnBuffer,
3536 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3538 ERR(": missing dwReserved1 registry data members\n") ;
3543 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
3545 sizeOfReturnBuffer = 255;
3547 /* Get dwReserved2 */
3548 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
3549 NULL, &returnType, (LPBYTE)returnBuffer,
3550 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3552 ERR(": missing dwReserved1 registry data members\n") ;
3557 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
3559 sizeOfReturnBuffer = 255;
3561 /* Get the path for this service provider */
3562 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
3563 NULL, NULL, (LPBYTE)returnBuffer,
3564 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
3566 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
3570 TRACE( "Loading %s\n", returnBuffer );
3571 return LoadLibraryA( returnBuffer );
3579 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
3582 LPDPSP_SPINIT SPInit;
3584 /* Initialize the service provider by calling SPInit */
3585 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
3587 if( SPInit == NULL )
3589 ERR( "Service provider doesn't provide SPInit interface?\n" );
3590 FreeLibrary( hServiceProvider );
3591 return DPERR_UNAVAILABLE;
3594 TRACE( "Calling SPInit (DP SP entry point)\n" );
3596 hr = (*SPInit)( &This->dp2->spData );
3600 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
3601 FreeLibrary( hServiceProvider );
3605 /* FIXME: Need to verify the sanity of the returned callback table
3606 * using IsBadCodePtr */
3607 This->dp2->bSPInitialized = TRUE;
3609 /* This interface is now initialized as a DP object */
3610 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
3612 /* Store the handle of the module so that we can unload it later */
3613 This->dp2->hServiceProvider = hServiceProvider;
3619 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
3622 LPSP_INIT DPLSPInit;
3624 /* Initialize the service provider by calling SPInit */
3625 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
3627 if( DPLSPInit == NULL )
3629 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
3630 FreeLibrary( hLobbyProvider );
3631 return DPERR_UNAVAILABLE;
3634 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
3636 hr = (*DPLSPInit)( &This->dp2->dplspData );
3640 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
3641 FreeLibrary( hLobbyProvider );
3645 /* FIXME: Need to verify the sanity of the returned callback table
3646 * using IsBadCodePtr */
3648 This->dp2->bDPLSPInitialized = TRUE;
3650 /* This interface is now initialized as a lobby object */
3651 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
3653 /* Store the handle of the module so that we can unload it later */
3654 This->dp2->hDPLobbyProvider = hLobbyProvider;
3659 static HRESULT WINAPI IDirectPlay4AImpl_InitializeConnection( IDirectPlay4A *iface,
3660 void *connection, DWORD flags )
3662 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3663 return IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, flags );
3666 static HRESULT WINAPI IDirectPlay4Impl_InitializeConnection( IDirectPlay4 *iface,
3667 void *connection, DWORD flags )
3669 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3672 const DWORD size = 80; /* FIXME: Need to calculate it correctly */
3673 BOOL is_dp_sp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
3676 TRACE( "(%p)->(%p,0x%08x)\n", This, connection, flags );
3679 return DPERR_INVALIDPARAMS;
3682 return DPERR_INVALIDFLAGS;
3684 if ( This->dp2->connectionInitialized != NO_PROVIDER )
3685 return DPERR_ALREADYINITIALIZED;
3687 /* Find out what the requested SP is and how large this buffer is */
3688 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, connection, size, &sp );
3692 ERR( "Invalid compound address?\n" );
3693 return DPERR_UNAVAILABLE;
3696 /* Load the service provider */
3697 servprov = DP_LoadSP( &sp, &This->dp2->spData, &is_dp_sp );
3701 ERR( "Unable to load service provider %s\n", debugstr_guid(&sp) );
3702 return DPERR_UNAVAILABLE;
3707 /* Fill in what we can of the Service Provider required information.
3708 * The rest was be done in DP_LoadSP
3710 This->dp2->spData.lpAddress = connection;
3711 This->dp2->spData.dwAddressSize = size;
3712 This->dp2->spData.lpGuid = &sp;
3713 hr = DP_InitializeDPSP( This, servprov );
3717 This->dp2->dplspData.lpAddress = connection;
3718 hr = DP_InitializeDPLSP( This, servprov );
3727 static HRESULT WINAPI IDirectPlay4AImpl_SecureOpen( IDirectPlay4A *iface,
3728 const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
3729 const DPCREDENTIALS *lpCredentials )
3731 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3732 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
3735 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
3736 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
3737 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
3739 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
3740 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
3743 static HRESULT WINAPI IDirectPlay4AImpl_SendChatMessage( IDirectPlay4A *iface, DPID from,
3744 DPID to, DWORD flags, DPCHAT *chatmsg )
3746 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3747 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
3751 static HRESULT WINAPI IDirectPlay4Impl_SendChatMessage( IDirectPlay4 *iface, DPID from, DPID to,
3752 DWORD flags, DPCHAT *chatmsg )
3754 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3755 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
3759 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupConnectionSettings( IDirectPlay4A *iface,
3760 DWORD flags, DPID group, DPLCONNECTION *connection )
3762 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3763 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
3767 static HRESULT WINAPI IDirectPlay4Impl_SetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
3768 DPID group, DPLCONNECTION *connection )
3770 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3771 FIXME( "(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
3775 static HRESULT WINAPI IDirectPlay4AImpl_StartSession( IDirectPlay4A *iface, DWORD dwFlags,
3778 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3779 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
3783 static HRESULT WINAPI IDirectPlay4Impl_StartSession( IDirectPlay4 *iface, DWORD flags, DPID group )
3785 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3786 FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, flags, group );
3790 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupFlags( IDirectPlay4A *iface, DPID idGroup,
3793 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3794 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
3798 static HRESULT WINAPI IDirectPlay4Impl_GetGroupFlags( IDirectPlay4 *iface, DPID group,
3801 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3802 FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, flags );
3806 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupParent( IDirectPlay4A *iface, DPID group,
3809 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3810 return IDirectPlayX_GetGroupParent( &This->IDirectPlay4_iface, group, parent );
3813 static HRESULT WINAPI IDirectPlay4Impl_GetGroupParent( IDirectPlay4 *iface, DPID group,
3816 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3819 TRACE( "(%p)->(0x%08x,%p)\n", This, group, parent );
3821 if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
3822 return DPERR_INVALIDGROUP;
3824 *parent = gdata->dpid;
3829 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAccount( IDirectPlay4A *iface, DPID player,
3830 DWORD flags, void *data, DWORD *size )
3832 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3833 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
3837 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAccount( IDirectPlay4 *iface, DPID player,
3838 DWORD flags, void *data, DWORD *size )
3840 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3841 FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
3845 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerFlags( IDirectPlay4A *iface, DPID idPlayer,
3848 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3849 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
3853 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerFlags( IDirectPlay4 *iface, DPID player,
3856 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3857 FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, flags );
3861 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
3862 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
3864 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3865 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
3869 static HRESULT WINAPI IDirectPlay4Impl_GetGroupOwner( IDirectPlay4 *iface, DPID group,
3872 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3873 FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, owner );
3877 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
3878 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
3880 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3881 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
3885 static HRESULT WINAPI IDirectPlay4Impl_SetGroupOwner( IDirectPlay4 *iface, DPID group ,
3888 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3889 FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, owner );
3893 static HRESULT DP_SendEx
3894 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
3895 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
3896 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
3898 BOOL bValidDestination = FALSE;
3900 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
3902 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
3903 dwTimeout, lpContext, lpdwMsgID, bAnsi );
3905 if( This->dp2->connectionInitialized == NO_PROVIDER )
3907 return DPERR_UNINITIALIZED;
3910 /* FIXME: Add parameter checking */
3911 /* FIXME: First call to this needs to acquire a message id which will be
3912 * used for multiple sends
3915 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
3917 /* Verify that the message is being sent from a valid local player. The
3918 * from player may be anonymous DPID_UNKNOWN
3920 if( idFrom != DPID_UNKNOWN )
3922 if( DP_FindPlayer( This, idFrom ) == NULL )
3924 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
3925 return DPERR_INVALIDPLAYER;
3929 /* Verify that the message is being sent to a valid player, group or to
3930 * everyone. If it's valid, send it to those players.
3932 if( idTo == DPID_ALLPLAYERS )
3934 bValidDestination = TRUE;
3936 /* See if SP has the ability to multicast. If so, use it */
3937 if( This->dp2->spData.lpCB->SendToGroupEx )
3939 FIXME( "Use group sendex to group 0\n" );
3941 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
3943 FIXME( "Use obsolete group send to group 0\n" );
3945 else /* No multicast, multiplicate */
3947 /* Send to all players we know about */
3948 FIXME( "Send to all players using EnumPlayersInGroup\n" );
3952 if( ( !bValidDestination ) &&
3953 ( DP_FindPlayer( This, idTo ) != NULL )
3956 /* Have the service provider send this message */
3957 /* FIXME: Could optimize for local interface sends */
3958 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
3959 dwTimeout, lpContext, lpdwMsgID );
3962 if( ( !bValidDestination ) &&
3963 ( DP_FindAnyGroup( This, idTo ) != NULL )
3966 bValidDestination = TRUE;
3968 /* See if SP has the ability to multicast. If so, use it */
3969 if( This->dp2->spData.lpCB->SendToGroupEx )
3971 FIXME( "Use group sendex\n" );
3973 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
3975 FIXME( "Use obsolete group send to group\n" );
3977 else /* No multicast, multiplicate */
3979 FIXME( "Send to all players using EnumPlayersInGroup\n" );
3987 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
3989 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
3990 if( dwWaitReturn != WAIT_OBJECT_0 )
3992 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
3998 if( !bValidDestination )
4000 return DPERR_INVALIDPLAYER;
4004 /* FIXME: Should return what the send returned */
4010 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4011 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4012 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4013 LPVOID lpContext, LPDWORD lpdwMsgID )
4015 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4016 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4017 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4020 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4021 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4022 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4023 LPVOID lpContext, LPDWORD lpdwMsgID )
4025 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4026 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4027 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4030 static HRESULT DP_SP_SendEx
4031 ( IDirectPlay2Impl* This, DWORD dwFlags,
4032 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4033 LPVOID lpContext, LPDWORD lpdwMsgID )
4037 FIXME( ": stub\n" );
4039 /* FIXME: This queuing should only be for async messages */
4041 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4042 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4044 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4046 /* FIXME: Need to queue based on priority */
4047 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4052 static HRESULT DP_IF_GetMessageQueue
4053 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4054 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4058 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4059 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4061 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4062 /* FIXME: What about sends which are not immediate? */
4064 if( This->dp2->spData.lpCB->GetMessageQueue )
4066 DPSP_GETMESSAGEQUEUEDATA data;
4068 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4070 /* FIXME: None of this is documented :( */
4072 data.lpISP = This->dp2->spData.lpISP;
4073 data.dwFlags = dwFlags;
4074 data.idFrom = idFrom;
4076 data.lpdwNumMsgs = lpdwNumMsgs;
4077 data.lpdwNumBytes = lpdwNumBytes;
4079 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4083 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4089 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4090 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4091 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4093 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4094 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4095 lpdwNumBytes, TRUE );
4098 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4099 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4100 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4102 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4103 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4104 lpdwNumBytes, FALSE );
4107 static HRESULT DP_IF_CancelMessage
4108 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4109 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4113 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4114 This, dwMsgID, dwFlags, bAnsi );
4116 if( This->dp2->spData.lpCB->Cancel )
4118 DPSP_CANCELDATA data;
4120 TRACE( "Calling SP Cancel\n" );
4122 /* FIXME: Undocumented callback */
4124 data.lpISP = This->dp2->spData.lpISP;
4125 data.dwFlags = dwFlags;
4126 data.lprglpvSPMsgID = NULL;
4127 data.cSPMsgID = dwMsgID;
4128 data.dwMinPriority = dwMinPriority;
4129 data.dwMaxPriority = dwMaxPriority;
4131 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4135 FIXME( "SP doesn't implement Cancel\n" );
4141 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4142 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4144 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4148 return DPERR_INVALIDFLAGS;
4153 dwFlags |= DPCANCELSEND_ALL;
4156 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4159 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4160 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4162 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4166 return DPERR_INVALIDFLAGS;
4171 dwFlags |= DPCANCELSEND_ALL;
4174 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4177 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4178 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4181 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4185 return DPERR_INVALIDFLAGS;
4188 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4189 dwMaxPriority, TRUE );
4192 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4193 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4196 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4200 return DPERR_INVALIDFLAGS;
4203 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4204 dwMaxPriority, FALSE );
4207 /* Note: Hack so we can reuse the old functions without compiler warnings */
4208 # define XCAST(fun) (void*)
4209 static const IDirectPlay4Vtbl dp4_vt =
4211 IDirectPlay4Impl_QueryInterface,
4212 IDirectPlay4Impl_AddRef,
4213 IDirectPlay4Impl_Release,
4214 IDirectPlay4Impl_AddPlayerToGroup,
4215 IDirectPlay4Impl_Close,
4216 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
4217 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
4218 IDirectPlay4Impl_DeletePlayerFromGroup,
4219 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
4220 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
4221 IDirectPlay4Impl_EnumGroupPlayers,
4222 IDirectPlay4Impl_EnumGroups,
4223 IDirectPlay4Impl_EnumPlayers,
4224 IDirectPlay4Impl_EnumSessions,
4225 IDirectPlay4Impl_GetCaps,
4226 IDirectPlay4Impl_GetGroupData,
4227 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
4228 IDirectPlay4Impl_GetMessageCount,
4229 IDirectPlay4Impl_GetPlayerAddress,
4230 IDirectPlay4Impl_GetPlayerCaps,
4231 IDirectPlay4Impl_GetPlayerData,
4232 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
4233 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
4234 IDirectPlay4Impl_Initialize,
4235 IDirectPlay4Impl_Open,
4236 XCAST(Receive)DirectPlay2WImpl_Receive,
4237 IDirectPlay4Impl_Send,
4238 IDirectPlay4Impl_SetGroupData,
4239 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
4240 IDirectPlay4Impl_SetPlayerData,
4241 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
4242 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
4243 IDirectPlay4Impl_AddGroupToGroup,
4244 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
4245 IDirectPlay4Impl_DeleteGroupFromGroup,
4246 IDirectPlay4Impl_EnumConnections,
4247 IDirectPlay4Impl_EnumGroupsInGroup,
4248 IDirectPlay4Impl_GetGroupConnectionSettings,
4249 IDirectPlay4Impl_InitializeConnection,
4250 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
4251 IDirectPlay4Impl_SendChatMessage,
4252 IDirectPlay4Impl_SetGroupConnectionSettings,
4253 IDirectPlay4Impl_StartSession,
4254 IDirectPlay4Impl_GetGroupFlags,
4255 IDirectPlay4Impl_GetGroupParent,
4256 IDirectPlay4Impl_GetPlayerAccount,
4257 IDirectPlay4Impl_GetPlayerFlags,
4258 IDirectPlay4Impl_GetGroupOwner,
4259 IDirectPlay4Impl_SetGroupOwner,
4260 DirectPlay4WImpl_SendEx,
4261 DirectPlay4WImpl_GetMessageQueue,
4262 DirectPlay4WImpl_CancelMessage,
4263 DirectPlay4WImpl_CancelPriority
4267 static const IDirectPlay4Vtbl dp4A_vt =
4269 IDirectPlay4AImpl_QueryInterface,
4270 IDirectPlay4AImpl_AddRef,
4271 IDirectPlay4AImpl_Release,
4272 IDirectPlay4AImpl_AddPlayerToGroup,
4273 IDirectPlay4AImpl_Close,
4274 IDirectPlay4AImpl_CreateGroup,
4275 IDirectPlay4AImpl_CreatePlayer,
4276 IDirectPlay4AImpl_DeletePlayerFromGroup,
4277 IDirectPlay4AImpl_DestroyGroup,
4278 IDirectPlay4AImpl_DestroyPlayer,
4279 IDirectPlay4AImpl_EnumGroupPlayers,
4280 IDirectPlay4AImpl_EnumGroups,
4281 IDirectPlay4AImpl_EnumPlayers,
4282 IDirectPlay4AImpl_EnumSessions,
4283 IDirectPlay4AImpl_GetCaps,
4284 IDirectPlay4AImpl_GetGroupData,
4285 IDirectPlay4AImpl_GetGroupName,
4286 IDirectPlay4AImpl_GetMessageCount,
4287 IDirectPlay4AImpl_GetPlayerAddress,
4288 IDirectPlay4AImpl_GetPlayerCaps,
4289 IDirectPlay4AImpl_GetPlayerData,
4290 IDirectPlay4AImpl_GetPlayerName,
4291 IDirectPlay4AImpl_GetSessionDesc,
4292 IDirectPlay4AImpl_Initialize,
4293 IDirectPlay4AImpl_Open,
4294 IDirectPlay4AImpl_Receive,
4295 IDirectPlay4AImpl_Send,
4296 IDirectPlay4AImpl_SetGroupData,
4297 IDirectPlay4AImpl_SetGroupName,
4298 IDirectPlay4AImpl_SetPlayerData,
4299 IDirectPlay4AImpl_SetPlayerName,
4300 IDirectPlay4AImpl_SetSessionDesc,
4301 IDirectPlay4AImpl_AddGroupToGroup,
4302 IDirectPlay4AImpl_CreateGroupInGroup,
4303 IDirectPlay4AImpl_DeleteGroupFromGroup,
4304 IDirectPlay4AImpl_EnumConnections,
4305 IDirectPlay4AImpl_EnumGroupsInGroup,
4306 IDirectPlay4AImpl_GetGroupConnectionSettings,
4307 IDirectPlay4AImpl_InitializeConnection,
4308 IDirectPlay4AImpl_SecureOpen,
4309 IDirectPlay4AImpl_SendChatMessage,
4310 IDirectPlay4AImpl_SetGroupConnectionSettings,
4311 IDirectPlay4AImpl_StartSession,
4312 IDirectPlay4AImpl_GetGroupFlags,
4313 IDirectPlay4AImpl_GetGroupParent,
4314 IDirectPlay4AImpl_GetPlayerAccount,
4315 IDirectPlay4AImpl_GetPlayerFlags,
4317 DirectPlay4AImpl_GetGroupOwner,
4318 DirectPlay4AImpl_SetGroupOwner,
4319 DirectPlay4AImpl_SendEx,
4320 DirectPlay4AImpl_GetMessageQueue,
4321 DirectPlay4AImpl_CancelMessage,
4322 DirectPlay4AImpl_CancelPriority
4325 HRESULT dplay_create( REFIID riid, void **ppv )
4327 IDirectPlayImpl *obj;
4330 TRACE( "(%s, %p)\n", debugstr_guid( riid ), ppv );
4333 obj = HeapAlloc( GetProcessHeap(), 0, sizeof( *obj ) );
4335 return DPERR_OUTOFMEMORY;
4337 obj->IDirectPlay4A_iface.lpVtbl = &dp4A_vt;
4338 obj->IDirectPlay4_iface.lpVtbl = &dp4_vt;
4343 InitializeCriticalSection( &obj->lock );
4344 obj->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlayImpl.lock");
4346 if ( DP_CreateDirectPlay2( obj ) )
4347 hr = IDirectPlayX_QueryInterface( &obj->IDirectPlay4A_iface, riid, ppv );
4349 hr = DPERR_NOMEMORY;
4350 IDirectPlayX_Release( &obj->IDirectPlay4A_iface );
4356 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
4360 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
4362 if( lpPlayer == NULL )
4364 return DPERR_INVALIDPLAYER;
4367 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
4372 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
4376 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
4378 if( lpPlayer == NULL )
4380 return DPERR_INVALIDPLAYER;
4383 lpPlayer->lpPData->lpSPPlayerData = lpData;
4388 /***************************************************************************
4389 * DirectPlayEnumerateAW
4391 * The pointer to the structure lpContext will be filled with the
4392 * appropriate data for each service offered by the OS. These services are
4393 * not necessarily available on this particular machine but are defined
4394 * as simple service providers under the "Service Providers" registry key.
4395 * This structure is then passed to lpEnumCallback for each of the different
4398 * This API is useful only for applications written using DirectX3 or
4399 * worse. It is superseded by IDirectPlay3::EnumConnections which also
4400 * gives information on the actual connections.
4402 * defn of a service provider:
4403 * A dynamic-link library used by DirectPlay to communicate over a network.
4404 * The service provider contains all the network-specific code required
4405 * to send and receive messages. Online services and network operators can
4406 * supply service providers to use specialized hardware, protocols, communications
4407 * media, and network resources.
4410 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
4411 LPDPENUMDPCALLBACKW lpEnumCallbackW,
4415 static const WCHAR searchSubKey[] = {
4416 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
4417 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
4418 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
4419 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
4420 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
4421 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
4426 char *descriptionA = NULL;
4427 DWORD max_sizeOfDescriptionA = 0;
4428 WCHAR *descriptionW = NULL;
4429 DWORD max_sizeOfDescriptionW = 0;
4431 if (!lpEnumCallbackA && !lpEnumCallbackW)
4433 return DPERR_INVALIDPARAMS;
4436 /* Need to loop over the service providers in the registry */
4437 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
4438 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
4440 /* Hmmm. Does this mean that there are no service providers? */
4441 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
4442 return DPERR_GENERIC;
4445 /* Traverse all the service providers we have available */
4449 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
4450 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
4451 HKEY hkServiceProvider;
4452 GUID serviceProviderGUID;
4453 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
4454 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
4457 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4458 NULL, NULL, NULL, &filetime);
4459 if (ret_value == ERROR_NO_MORE_ITEMS)
4461 else if (ret_value != ERROR_SUCCESS)
4463 ERR(": could not enumerate on service provider key.\n");
4464 return DPERR_EXCEPTION;
4466 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
4468 /* Open the key for this service provider */
4469 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
4471 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
4475 /* Get the GUID from the registry */
4476 if (RegQueryValueExW(hkServiceProvider, guidKey,
4477 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
4479 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
4482 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
4484 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
4487 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
4489 /* The enumeration will return FALSE if we are not to continue.
4491 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
4492 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
4493 * I think that it simply means that they are in-line with DirectX 6.0
4495 if (lpEnumCallbackA)
4497 DWORD sizeOfDescription = 0;
4499 /* Note that this is the A case of this function, so use the A variant to get the description string */
4500 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
4501 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
4503 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
4506 if (sizeOfDescription > max_sizeOfDescriptionA)
4508 HeapFree(GetProcessHeap(), 0, descriptionA);
4509 max_sizeOfDescriptionA = sizeOfDescription;
4511 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
4512 RegQueryValueExA(hkServiceProvider, "DescriptionA",
4513 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
4515 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
4520 DWORD sizeOfDescription = 0;
4522 if (RegQueryValueExW(hkServiceProvider, descW,
4523 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
4525 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
4528 if (sizeOfDescription > max_sizeOfDescriptionW)
4530 HeapFree(GetProcessHeap(), 0, descriptionW);
4531 max_sizeOfDescriptionW = sizeOfDescription;
4533 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
4534 RegQueryValueExW(hkServiceProvider, descW,
4535 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
4537 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
4545 HeapFree(GetProcessHeap(), 0, descriptionA);
4546 HeapFree(GetProcessHeap(), 0, descriptionW);
4551 /***************************************************************************
4552 * DirectPlayEnumerate [DPLAYX.9]
4553 * DirectPlayEnumerateA [DPLAYX.2]
4555 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
4557 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
4559 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
4562 /***************************************************************************
4563 * DirectPlayEnumerateW [DPLAYX.3]
4565 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
4567 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
4569 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
4572 typedef struct tagCreateEnum
4576 } CreateEnumData, *lpCreateEnumData;
4578 /* Find and copy the matching connection for the SP guid */
4579 static BOOL CALLBACK cbDPCreateEnumConnections(
4581 LPVOID lpConnection,
4582 DWORD dwConnectionSize,
4587 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
4589 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
4591 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
4593 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4595 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
4597 /* Found the record that we were looking for */
4601 /* Haven't found what were looking for yet */
4606 /***************************************************************************
4607 * DirectPlayCreate [DPLAYX.1]
4610 HRESULT WINAPI DirectPlayCreate
4611 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
4614 LPDIRECTPLAY3A lpDP3A;
4615 CreateEnumData cbData;
4617 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
4621 return CLASS_E_NOAGGREGATION;
4624 if( (lplpDP == NULL) || (lpGUID == NULL) )
4626 return DPERR_INVALIDPARAMS;
4629 /* Create an IDirectPlay object. We don't support that so we'll cheat and
4630 give them an IDirectPlay2A object and hope that doesn't cause problems */
4631 if ( dplay_create( &IID_IDirectPlay2A, (void**)lplpDP ) != DP_OK )
4632 return DPERR_UNAVAILABLE;
4634 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
4636 /* The GUID_NULL means don't bind a service provider. Just return the
4641 /* Bind the desired service provider since lpGUID is non NULL */
4642 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
4644 /* We're going to use a DP3 interface */
4645 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
4649 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
4653 cbData.lpConn = NULL;
4654 cbData.lpGuid = lpGUID;
4656 /* We were given a service provider, find info about it... */
4657 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
4658 &cbData, DPCONNECTION_DIRECTPLAY );
4659 if( ( FAILED(hr) ) ||
4660 ( cbData.lpConn == NULL )
4663 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
4664 IDirectPlayX_Release( lpDP3A );
4665 return DPERR_UNAVAILABLE;
4668 /* Initialize the service provider */
4669 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
4672 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
4673 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
4674 IDirectPlayX_Release( lpDP3A );
4678 /* Release our version of the interface now that we're done with it */
4679 IDirectPlayX_Release( lpDP3A );
4680 HeapFree( GetProcessHeap(), 0, cbData.lpConn );