dplayx: Merge the DirectPlay QueryInterface helper.
[wine.git] / dlls / dplayx / dplay.c
blob8a95538bed3fbf01d8522fe02188cf3188d69b9f
1 /* Direct Play 2,3,4 Implementation
3 * Copyright 1998,1999,2000,2001 - Peter Hunnisett
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define COBJMACROS
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <string.h>
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winerror.h"
31 #include "winbase.h"
32 #include "winnt.h"
33 #include "winreg.h"
34 #include "winnls.h"
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
38 #include "dpinit.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,
70 DWORD dwPlayerType,
71 LPCDPNAME lpName,
72 DWORD dwFlags,
73 LPVOID lpContext );
74 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
75 static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
76 LPCDPNAME lpName, DWORD dwFlags,
77 LPVOID lpContext );
78 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
80 /* Helper methods for player/group interfaces */
81 static HRESULT DP_IF_DeletePlayerFromGroup
82 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
83 DPID idPlayer, BOOL bAnsi );
84 static HRESULT DP_IF_CreatePlayer
85 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
86 LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
87 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
88 static HRESULT DP_IF_DestroyGroup
89 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
90 static HRESULT DP_IF_DestroyPlayer
91 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
92 static HRESULT DP_IF_EnumGroupPlayers
93 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
94 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
95 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
96 static HRESULT DP_IF_GetGroupData
97 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
98 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
99 static HRESULT DP_IF_GetGroupName
100 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
101 LPDWORD lpdwDataSize, BOOL bAnsi );
102 static HRESULT DP_IF_GetPlayerData
103 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
104 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
105 static HRESULT DP_IF_GetPlayerName
106 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
107 LPDWORD lpdwDataSize, BOOL bAnsi );
108 static HRESULT DP_IF_SetGroupName
109 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
110 DWORD dwFlags, BOOL bAnsi );
111 static HRESULT DP_IF_SetPlayerData
112 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
113 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
114 static HRESULT DP_IF_SetPlayerName
115 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
116 DWORD dwFlags, BOOL bAnsi );
117 static HRESULT DP_IF_AddGroupToGroup
118 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
119 static HRESULT DP_IF_CreateGroup
120 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
121 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
122 DWORD dwFlags, BOOL bAnsi );
123 static HRESULT DP_IF_CreateGroupInGroup
124 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
125 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
126 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
127 static HRESULT DP_IF_AddPlayerToGroup
128 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
129 DPID idPlayer, BOOL bAnsi );
130 static HRESULT DP_IF_DeleteGroupFromGroup
131 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
132 static HRESULT DP_SetSessionDesc
133 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
134 DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
135 static HRESULT DP_SecureOpen
136 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
137 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
138 BOOL bAnsi );
139 static HRESULT DP_SendEx
140 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
141 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
142 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
143 static HRESULT DP_IF_Receive
144 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
145 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
146 static HRESULT DP_IF_GetMessageQueue
147 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
148 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
149 static HRESULT DP_SP_SendEx
150 ( IDirectPlay2Impl* This, DWORD dwFlags,
151 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
152 LPVOID lpContext, LPDWORD lpdwMsgID );
153 static HRESULT DP_IF_SetGroupData
154 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
155 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
156 static HRESULT DP_IF_GetPlayerCaps
157 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
158 DWORD dwFlags );
159 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
160 static HRESULT DP_IF_CancelMessage
161 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
162 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
163 static HRESULT DP_IF_EnumGroupsInGroup
164 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
165 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
166 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
167 static HRESULT DP_IF_GetGroupParent
168 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
169 BOOL bAnsi );
170 static HRESULT DP_IF_GetCaps
171 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
172 static HRESULT DP_IF_EnumSessions
173 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
174 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
175 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
176 static HRESULT DP_IF_InitializeConnection
177 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
178 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
179 LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
180 DWORD dwFlags, LPVOID lpContext );
181 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
182 LPDWORD lpdwBufSize );
186 static inline DPID DP_NextObjectId(void);
187 static DPID DP_GetRemoteNextObjectId(void);
189 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
190 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
191 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
194 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
195 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
196 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
203 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
204 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
205 we don't have to change much */
206 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
208 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
209 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
211 /* Strip out all dwFlags values for CREATEPLAYER msg */
212 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
214 static LONG kludgePlayerGroupId = 1000;
217 static inline IDirectPlayImpl *impl_from_IDirectPlay4A( IDirectPlay4A *iface )
219 return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4A_iface );
222 static inline IDirectPlayImpl *impl_from_IDirectPlay4( IDirectPlay4 *iface )
224 return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4_iface );
227 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
229 IDirectPlay2AImpl *This = lpDP;
231 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
232 if ( This->dp2 == NULL )
234 return FALSE;
237 This->dp2->bConnectionOpen = FALSE;
239 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
240 This->dp2->dwEnumSessionLock = 0;
242 This->dp2->bHostInterface = FALSE;
244 DPQ_INIT(This->dp2->receiveMsgs);
245 DPQ_INIT(This->dp2->sendMsgs);
246 DPQ_INIT(This->dp2->repliesExpected);
248 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
250 /* FIXME: Memory leak */
251 return FALSE;
254 /* Provide an initial session desc with nothing in it */
255 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
256 HEAP_ZERO_MEMORY,
257 sizeof( *This->dp2->lpSessionDesc ) );
258 if( This->dp2->lpSessionDesc == NULL )
260 /* FIXME: Memory leak */
261 return FALSE;
263 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
265 /* We are emulating a dp 6 implementation */
266 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
268 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
269 sizeof( *This->dp2->spData.lpCB ) );
270 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
271 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
273 /* This is the pointer to the service provider */
274 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
275 (LPVOID*)&This->dp2->spData.lpISP, This ) )
278 /* FIXME: Memory leak */
279 return FALSE;
282 /* Setup lobby provider information */
283 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
284 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
285 sizeof( *This->dp2->dplspData.lpCB ) );
286 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
288 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
289 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
292 /* FIXME: Memory leak */
293 return FALSE;
296 return TRUE;
299 /* Definition of the global function in dplayx_queue.h. #
300 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
301 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
303 HeapFree( GetProcessHeap(), 0, elem );
306 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
308 IDirectPlay2AImpl *This = lpDP;
310 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
312 TerminateThread( This->dp2->hEnumSessionThread, 0 );
313 CloseHandle( This->dp2->hEnumSessionThread );
316 /* Finish with the SP - have it shutdown */
317 if( This->dp2->spData.lpCB->ShutdownEx )
319 DPSP_SHUTDOWNDATA data;
321 TRACE( "Calling SP ShutdownEx\n" );
323 data.lpISP = This->dp2->spData.lpISP;
325 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
327 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
329 TRACE( "Calling obsolete SP Shutdown\n" );
330 (*This->dp2->spData.lpCB->Shutdown)();
333 /* Unload the SP (if it exists) */
334 if( This->dp2->hServiceProvider != 0 )
336 FreeLibrary( This->dp2->hServiceProvider );
339 /* Unload the Lobby Provider (if it exists) */
340 if( This->dp2->hDPLobbyProvider != 0 )
342 FreeLibrary( This->dp2->hDPLobbyProvider );
345 /* FIXME: Need to delete receive and send msgs queue contents */
347 NS_DeleteSessionCache( This->dp2->lpNameServerData );
349 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
351 IDirectPlaySP_Release( This->dp2->spData.lpISP );
353 /* Delete the contents */
354 HeapFree( GetProcessHeap(), 0, This->dp2 );
356 return TRUE;
359 static void dplay_destroy(IDirectPlayImpl *obj)
361 DP_DestroyDirectPlay2( obj );
362 obj->lock.DebugInfo->Spare[0] = 0;
363 DeleteCriticalSection( &obj->lock );
364 HeapFree( GetProcessHeap(), 0, obj );
367 static inline DPID DP_NextObjectId(void)
369 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
372 /* *lplpReply will be non NULL iff there is something to reply */
373 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
374 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
375 WORD wCommandId, WORD wVersion,
376 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
378 TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
379 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
380 wVersion );
382 switch( wCommandId )
384 /* Name server needs to handle this request */
385 case DPMSGCMD_ENUMSESSIONSREQUEST:
386 /* Reply expected */
387 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
388 break;
390 /* Name server needs to handle this request */
391 case DPMSGCMD_ENUMSESSIONSREPLY:
392 /* No reply expected */
393 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
394 This->dp2->spData.dwSPHeaderSize,
395 lpcMessageBody,
396 This->dp2->lpNameServerData );
397 break;
399 case DPMSGCMD_REQUESTNEWPLAYERID:
401 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = lpcMessageBody;
403 LPDPMSG_NEWPLAYERIDREPLY lpReply;
405 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
407 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
409 FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
410 lpcMsg->dwFlags );
412 /* Setup the reply */
413 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
414 This->dp2->spData.dwSPHeaderSize );
416 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
417 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
418 lpReply->envelope.wVersion = DPMSGVER_DP6;
420 lpReply->dpidNewPlayerId = DP_NextObjectId();
422 TRACE( "Allocating new playerid 0x%08x from remote request\n",
423 lpReply->dpidNewPlayerId );
424 break;
427 case DPMSGCMD_GETNAMETABLEREPLY:
428 case DPMSGCMD_NEWPLAYERIDREPLY:
429 #if 0
430 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
431 DebugBreak();
432 #endif
433 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
434 break;
436 #if 1
437 case DPMSGCMD_JUSTENVELOPE:
438 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
439 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
440 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
441 #endif
443 case DPMSGCMD_FORWARDADDPLAYER:
444 #if 0
445 DebugBreak();
446 #endif
447 #if 1
448 TRACE( "Sending message to self to get my addr\n" );
449 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
450 #endif
451 break;
453 case DPMSGCMD_FORWARDADDPLAYERNACK:
454 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
455 break;
457 default:
458 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
459 DebugBreak();
460 break;
463 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
465 return DP_OK;
469 static HRESULT DP_IF_AddPlayerToGroup
470 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
471 DPID idPlayer, BOOL bAnsi )
473 lpGroupData lpGData;
474 lpPlayerList lpPList;
475 lpPlayerList lpNewPList;
477 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
478 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
480 if( This->dp2->connectionInitialized == NO_PROVIDER )
482 return DPERR_UNINITIALIZED;
485 /* Find the group */
486 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
488 return DPERR_INVALIDGROUP;
491 /* Find the player */
492 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
494 return DPERR_INVALIDPLAYER;
497 /* Create a player list (ie "shortcut" ) */
498 lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
499 if( lpNewPList == NULL )
501 return DPERR_CANTADDPLAYER;
504 /* Add the shortcut */
505 lpPList->lpPData->uRef++;
506 lpNewPList->lpPData = lpPList->lpPData;
508 /* Add the player to the list of players for this group */
509 DPQ_INSERT(lpGData->players,lpNewPList,players);
511 /* Let the SP know that we've added a player to the group */
512 if( This->dp2->spData.lpCB->AddPlayerToGroup )
514 DPSP_ADDPLAYERTOGROUPDATA data;
516 TRACE( "Calling SP AddPlayerToGroup\n" );
518 data.idPlayer = idPlayer;
519 data.idGroup = idGroup;
520 data.lpISP = This->dp2->spData.lpISP;
522 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
525 /* Inform all other peers of the addition of player to the group. If there are
526 * no peers keep this event quiet.
527 * Also, if this event was the result of another machine sending it to us,
528 * don't bother rebroadcasting it.
530 if( ( lpMsgHdr == NULL ) &&
531 This->dp2->lpSessionDesc &&
532 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
534 DPMSG_ADDPLAYERTOGROUP msg;
535 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
537 msg.dpIdGroup = idGroup;
538 msg.dpIdPlayer = idPlayer;
540 /* FIXME: Correct to just use send effectively? */
541 /* FIXME: Should size include data w/ message or just message "header" */
542 /* FIXME: Check return code */
543 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
546 return DP_OK;
549 static HRESULT WINAPI IDirectPlay4AImpl_QueryInterface( IDirectPlay4A *iface, REFIID riid,
550 void **ppv )
552 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
553 return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
556 static HRESULT WINAPI IDirectPlay4Impl_QueryInterface( IDirectPlay4 *iface, REFIID riid,
557 void **ppv )
559 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
561 if ( IsEqualGUID( &IID_IUnknown, riid ) )
563 TRACE( "(%p)->(IID_IUnknown %p)\n", This, ppv );
564 *ppv = &This->IDirectPlay4A_iface;
566 else if ( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
568 TRACE( "(%p)->(IID_IDirectPlay2A %p)\n", This, ppv );
569 *ppv = &This->IDirectPlay4A_iface;
571 else if ( IsEqualGUID( &IID_IDirectPlay2, riid ) )
573 TRACE( "(%p)->(IID_IDirectPlay2 %p)\n", This, ppv );
574 *ppv = &This->IDirectPlay4_iface;
576 else if ( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
578 TRACE( "(%p)->(IID_IDirectPlay3A %p)\n", This, ppv );
579 *ppv = &This->IDirectPlay4A_iface;
581 else if ( IsEqualGUID( &IID_IDirectPlay3, riid ) )
583 TRACE( "(%p)->(IID_IDirectPlay3 %p)\n", This, ppv );
584 *ppv = &This->IDirectPlay4_iface;
586 else if ( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
588 TRACE( "(%p)->(IID_IDirectPlay4A %p)\n", This, ppv );
589 *ppv = &This->IDirectPlay4A_iface;
591 else if ( IsEqualGUID( &IID_IDirectPlay4, riid ) )
593 TRACE( "(%p)->(IID_IDirectPlay4 %p)\n", This, ppv );
594 *ppv = &This->IDirectPlay4_iface;
596 else
598 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
599 *ppv = NULL;
600 return E_NOINTERFACE;
603 IUnknown_AddRef((IUnknown*)*ppv);
604 return S_OK;
607 static ULONG WINAPI IDirectPlay4AImpl_AddRef(IDirectPlay4A *iface)
609 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
610 ULONG ref = InterlockedIncrement( &This->ref4A );
612 TRACE( "(%p) ref4A=%d\n", This, ref );
614 if ( ref == 1 )
615 InterlockedIncrement( &This->numIfaces );
617 return ref;
620 static ULONG WINAPI IDirectPlay4Impl_AddRef(IDirectPlay4 *iface)
622 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
623 ULONG ref = InterlockedIncrement( &This->ref4 );
625 TRACE( "(%p) ref4=%d\n", This, ref );
627 if ( ref == 1 )
628 InterlockedIncrement( &This->numIfaces );
630 return ref;
633 static ULONG WINAPI IDirectPlay4AImpl_Release(IDirectPlay4A *iface)
635 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
636 ULONG ref = InterlockedDecrement( &This->ref4A );
638 TRACE( "(%p) ref4A=%d\n", This, ref );
640 if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
641 dplay_destroy( This );
643 return ref;
646 static ULONG WINAPI IDirectPlay4Impl_Release(IDirectPlay4 *iface)
648 IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
649 ULONG ref = InterlockedDecrement( &This->ref4 );
651 TRACE( "(%p) ref4=%d\n", This, ref );
653 if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
654 dplay_destroy( This );
656 return ref;
659 static HRESULT WINAPI IDirectPlay4AImpl_AddPlayerToGroup( IDirectPlay4A *iface, DPID idGroup,
660 DPID idPlayer )
662 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
663 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
666 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
667 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
669 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
670 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
673 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
675 HRESULT hr = DP_OK;
677 TRACE("(%p)->(%u)\n", This, bAnsi );
679 /* FIXME: Need to find a new host I assume (how?) */
680 /* FIXME: Need to destroy all local groups */
681 /* FIXME: Need to migrate all remotely visible players to the new host */
683 /* Invoke the SP callback to inform of session close */
684 if( This->dp2->spData.lpCB->CloseEx )
686 DPSP_CLOSEDATA data;
688 TRACE( "Calling SP CloseEx\n" );
690 data.lpISP = This->dp2->spData.lpISP;
692 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
695 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
697 TRACE( "Calling SP Close (obsolete interface)\n" );
699 hr = (*This->dp2->spData.lpCB->Close)();
702 return hr;
705 static HRESULT WINAPI IDirectPlay4AImpl_Close( IDirectPlay4A *iface )
707 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
708 return DP_IF_Close( This, TRUE );
711 static HRESULT WINAPI DirectPlay2WImpl_Close
712 ( LPDIRECTPLAY2 iface )
714 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
715 return DP_IF_Close( This, FALSE );
718 static
719 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
720 const DPNAME *lpName, DWORD dwFlags,
721 DPID idParent, BOOL bAnsi )
723 lpGroupData lpGData;
725 /* Allocate the new space and add to end of high level group list */
726 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
728 if( lpGData == NULL )
730 return NULL;
733 DPQ_INIT(lpGData->groups);
734 DPQ_INIT(lpGData->players);
736 /* Set the desired player ID - no sanity checking to see if it exists */
737 lpGData->dpid = *lpid;
739 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
741 /* FIXME: Should we check that the parent exists? */
742 lpGData->parent = idParent;
744 /* FIXME: Should we validate the dwFlags? */
745 lpGData->dwFlags = dwFlags;
747 TRACE( "Created group id 0x%08x\n", *lpid );
749 return lpGData;
752 /* This method assumes that all links to it are already deleted */
753 static void
754 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
756 lpGroupList lpGList;
758 TRACE( "(%p)->(0x%08x)\n", This, dpid );
760 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
762 if( lpGList == NULL )
764 ERR( "DPID 0x%08x not found\n", dpid );
765 return;
768 if( --(lpGList->lpGData->uRef) )
770 FIXME( "Why is this not the last reference to group?\n" );
771 DebugBreak();
774 /* Delete player */
775 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
776 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
778 /* Remove and Delete Player List object */
779 HeapFree( GetProcessHeap(), 0, lpGList );
783 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
785 lpGroupList lpGroups;
787 TRACE( "(%p)->(0x%08x)\n", This, dpid );
789 if( dpid == DPID_SYSTEM_GROUP )
791 return This->dp2->lpSysGroup;
793 else
795 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
798 if( lpGroups == NULL )
800 return NULL;
803 return lpGroups->lpGData;
806 static HRESULT DP_IF_CreateGroup
807 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
808 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
809 DWORD dwFlags, BOOL bAnsi )
811 lpGroupData lpGData;
813 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
814 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
815 dwFlags, bAnsi );
817 if( This->dp2->connectionInitialized == NO_PROVIDER )
819 return DPERR_UNINITIALIZED;
822 /* If the name is not specified, we must provide one */
823 if( DPID_UNKNOWN == *lpidGroup )
825 /* If we are the name server, we decide on the group ids. If not, we
826 * must ask for one before attempting a creation.
828 if( This->dp2->bHostInterface )
830 *lpidGroup = DP_NextObjectId();
832 else
834 *lpidGroup = DP_GetRemoteNextObjectId();
838 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
839 DPID_NOPARENT_GROUP, bAnsi );
841 if( lpGData == NULL )
843 return DPERR_CANTADDPLAYER; /* yes player not group */
846 if( DPID_SYSTEM_GROUP == *lpidGroup )
848 This->dp2->lpSysGroup = lpGData;
849 TRACE( "Inserting system group\n" );
851 else
853 /* Insert into the system group */
854 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
855 lpGroup->lpGData = lpGData;
857 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
860 /* Something is now referencing this data */
861 lpGData->uRef++;
863 /* Set all the important stuff for the group */
864 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
866 /* FIXME: We should only create the system group if GetCaps returns
867 * DPCAPS_GROUPOPTIMIZED.
870 /* Let the SP know that we've created this group */
871 if( This->dp2->spData.lpCB->CreateGroup )
873 DPSP_CREATEGROUPDATA data;
874 DWORD dwCreateFlags = 0;
876 TRACE( "Calling SP CreateGroup\n" );
878 if( *lpidGroup == DPID_NOPARENT_GROUP )
879 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
881 if( lpMsgHdr == NULL )
882 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
884 if( dwFlags & DPGROUP_HIDDEN )
885 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
887 data.idGroup = *lpidGroup;
888 data.dwFlags = dwCreateFlags;
889 data.lpSPMessageHeader = lpMsgHdr;
890 data.lpISP = This->dp2->spData.lpISP;
892 (*This->dp2->spData.lpCB->CreateGroup)( &data );
895 /* Inform all other peers of the creation of a new group. If there are
896 * no peers keep this event quiet.
897 * Also if this message was sent to us, don't rebroadcast.
899 if( ( lpMsgHdr == NULL ) &&
900 This->dp2->lpSessionDesc &&
901 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
903 DPMSG_CREATEPLAYERORGROUP msg;
904 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
906 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
907 msg.dpId = *lpidGroup;
908 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
909 msg.lpData = lpData;
910 msg.dwDataSize = dwDataSize;
911 msg.dpnName = *lpGroupName;
912 msg.dpIdParent = DPID_NOPARENT_GROUP;
913 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
915 /* FIXME: Correct to just use send effectively? */
916 /* FIXME: Should size include data w/ message or just message "header" */
917 /* FIXME: Check return code */
918 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
919 0, 0, NULL, NULL, bAnsi );
922 return DP_OK;
925 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroup( IDirectPlay4A *iface, DPID *lpidGroup,
926 DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
928 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
930 *lpidGroup = DPID_UNKNOWN;
932 return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
933 TRUE );
936 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
937 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
938 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
940 *lpidGroup = DPID_UNKNOWN;
942 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
943 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
947 static void
948 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
949 LPVOID lpData, DWORD dwDataSize )
951 /* Clear out the data with this player */
952 if( dwFlags & DPSET_LOCAL )
954 if ( lpGData->dwLocalDataSize != 0 )
956 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
957 lpGData->lpLocalData = NULL;
958 lpGData->dwLocalDataSize = 0;
961 else
963 if( lpGData->dwRemoteDataSize != 0 )
965 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
966 lpGData->lpRemoteData = NULL;
967 lpGData->dwRemoteDataSize = 0;
971 /* Reallocate for new data */
972 if( lpData != NULL )
974 if( dwFlags & DPSET_LOCAL )
976 lpGData->lpLocalData = lpData;
977 lpGData->dwLocalDataSize = dwDataSize;
979 else
981 lpGData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
982 CopyMemory( lpGData->lpRemoteData, lpData, dwDataSize );
983 lpGData->dwRemoteDataSize = dwDataSize;
989 /* This function will just create the storage for the new player. */
990 static
991 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
992 LPDPNAME lpName, DWORD dwFlags,
993 HANDLE hEvent, BOOL bAnsi )
995 lpPlayerData lpPData;
997 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
999 /* Allocate the storage for the player and associate it with list element */
1000 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1001 if( lpPData == NULL )
1003 return NULL;
1006 /* Set the desired player ID */
1007 lpPData->dpid = *lpid;
1009 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1011 lpPData->dwFlags = dwFlags;
1013 /* If we were given an event handle, duplicate it */
1014 if( hEvent != 0 )
1016 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1017 GetCurrentProcess(), &lpPData->hEvent,
1018 0, FALSE, DUPLICATE_SAME_ACCESS )
1021 /* FIXME: Memory leak */
1022 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1026 /* Initialize the SP data section */
1027 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1029 TRACE( "Created player id 0x%08x\n", *lpid );
1031 if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1032 This->dp2->lpSessionDesc->dwCurrentPlayers++;
1034 return lpPData;
1037 /* Delete the contents of the DPNAME struct */
1038 static void
1039 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1041 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1042 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1045 /* This method assumes that all links to it are already deleted */
1046 static void
1047 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1049 lpPlayerList lpPList;
1051 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1053 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1055 if( lpPList == NULL )
1057 ERR( "DPID 0x%08x not found\n", dpid );
1058 return;
1061 /* Verify that this is the last reference to the data */
1062 if( --(lpPList->lpPData->uRef) )
1064 FIXME( "Why is this not the last reference to player?\n" );
1065 DebugBreak();
1068 /* Delete player */
1069 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1071 CloseHandle( lpPList->lpPData->hEvent );
1072 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1074 /* Delete Player List object */
1075 HeapFree( GetProcessHeap(), 0, lpPList );
1078 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1080 lpPlayerList lpPlayers;
1082 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1084 if(This->dp2->lpSysGroup == NULL)
1085 return NULL;
1087 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1089 return lpPlayers;
1092 /* Basic area for Dst must already be allocated */
1093 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1095 if( lpSrc == NULL )
1097 ZeroMemory( lpDst, sizeof( *lpDst ) );
1098 lpDst->dwSize = sizeof( *lpDst );
1099 return TRUE;
1102 if( lpSrc->dwSize != sizeof( *lpSrc) )
1104 return FALSE;
1107 /* Delete any existing pointers */
1108 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1109 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1111 /* Copy as required */
1112 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1114 if( bAnsi )
1116 if( lpSrc->u1.lpszShortNameA )
1118 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1119 strlen(lpSrc->u1.lpszShortNameA)+1 );
1120 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1122 if( lpSrc->u2.lpszLongNameA )
1124 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1125 strlen(lpSrc->u2.lpszLongNameA)+1 );
1126 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1129 else
1131 if( lpSrc->u1.lpszShortNameA )
1133 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1134 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1135 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1137 if( lpSrc->u2.lpszLongNameA )
1139 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1140 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1141 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1145 return TRUE;
1148 static void
1149 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1150 LPVOID lpData, DWORD dwDataSize )
1152 /* Clear out the data with this player */
1153 if( dwFlags & DPSET_LOCAL )
1155 if ( lpPData->dwLocalDataSize != 0 )
1157 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1158 lpPData->lpLocalData = NULL;
1159 lpPData->dwLocalDataSize = 0;
1162 else
1164 if( lpPData->dwRemoteDataSize != 0 )
1166 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1167 lpPData->lpRemoteData = NULL;
1168 lpPData->dwRemoteDataSize = 0;
1172 /* Reallocate for new data */
1173 if( lpData != NULL )
1176 if( dwFlags & DPSET_LOCAL )
1178 lpPData->lpLocalData = lpData;
1179 lpPData->dwLocalDataSize = dwDataSize;
1181 else
1183 lpPData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
1184 CopyMemory( lpPData->lpRemoteData, lpData, dwDataSize );
1185 lpPData->dwRemoteDataSize = dwDataSize;
1191 static HRESULT DP_IF_CreatePlayer
1192 ( IDirectPlay2Impl* This,
1193 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1194 LPDPID lpidPlayer,
1195 LPDPNAME lpPlayerName,
1196 HANDLE hEvent,
1197 LPVOID lpData,
1198 DWORD dwDataSize,
1199 DWORD dwFlags,
1200 BOOL bAnsi )
1202 HRESULT hr = DP_OK;
1203 lpPlayerData lpPData;
1204 lpPlayerList lpPList;
1205 DWORD dwCreateFlags = 0;
1207 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1208 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1209 dwDataSize, dwFlags, bAnsi );
1210 if( This->dp2->connectionInitialized == NO_PROVIDER )
1212 return DPERR_UNINITIALIZED;
1215 if( dwFlags == 0 )
1217 dwFlags = DPPLAYER_SPECTATOR;
1220 if( lpidPlayer == NULL )
1222 return DPERR_INVALIDPARAMS;
1226 /* Determine the creation flags for the player. These will be passed
1227 * to the name server if requesting a player id and to the SP when
1228 * informing it of the player creation
1231 if( dwFlags & DPPLAYER_SERVERPLAYER )
1233 if( *lpidPlayer == DPID_SERVERPLAYER )
1235 /* Server player for the host interface */
1236 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1238 else if( *lpidPlayer == DPID_NAME_SERVER )
1240 /* Name server - master of everything */
1241 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1243 else
1245 /* Server player for a non host interface */
1246 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1250 if( lpMsgHdr == NULL )
1251 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1254 /* Verify we know how to handle all the flags */
1255 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1256 ( dwFlags & DPPLAYER_SPECTATOR )
1260 /* Assume non fatal failure */
1261 ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1264 /* If the name is not specified, we must provide one */
1265 if( *lpidPlayer == DPID_UNKNOWN )
1267 /* If we are the session master, we dish out the group/player ids */
1268 if( This->dp2->bHostInterface )
1270 *lpidPlayer = DP_NextObjectId();
1272 else
1274 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1276 if( FAILED(hr) )
1278 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1279 return hr;
1283 else
1285 /* FIXME: Would be nice to perhaps verify that we don't already have
1286 * this player.
1290 /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
1291 player total */
1292 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1293 hEvent, bAnsi );
1295 if( lpPData == NULL )
1297 return DPERR_CANTADDPLAYER;
1300 /* Create the list object and link it in */
1301 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1302 if( lpPList == NULL )
1304 FIXME( "Memory leak\n" );
1305 return DPERR_CANTADDPLAYER;
1308 lpPData->uRef = 1;
1309 lpPList->lpPData = lpPData;
1311 /* Add the player to the system group */
1312 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1314 /* Update the information and send it to all players in the session */
1315 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1317 /* Let the SP know that we've created this player */
1318 if( This->dp2->spData.lpCB->CreatePlayer )
1320 DPSP_CREATEPLAYERDATA data;
1322 data.idPlayer = *lpidPlayer;
1323 data.dwFlags = dwCreateFlags;
1324 data.lpSPMessageHeader = lpMsgHdr;
1325 data.lpISP = This->dp2->spData.lpISP;
1327 TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1328 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1330 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1333 if( FAILED(hr) )
1335 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1336 return hr;
1339 /* Now let the SP know that this player is a member of the system group */
1340 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1342 DPSP_ADDPLAYERTOGROUPDATA data;
1344 data.idPlayer = *lpidPlayer;
1345 data.idGroup = DPID_SYSTEM_GROUP;
1346 data.lpISP = This->dp2->spData.lpISP;
1348 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1350 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1353 if( FAILED(hr) )
1355 ERR( "Failed to add player to sys group with sp: %s\n",
1356 DPLAYX_HresultToString(hr) );
1357 return hr;
1360 #if 1
1361 if( This->dp2->bHostInterface == FALSE )
1363 /* Let the name server know about the creation of this player */
1364 /* FIXME: Is this only to be done for the creation of a server player or
1365 * is this used for regular players? If only for server players, move
1366 * this call to DP_SecureOpen(...);
1368 #if 0
1369 TRACE( "Sending message to self to get my addr\n" );
1370 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1371 #endif
1373 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1375 #else
1376 /* Inform all other peers of the creation of a new player. If there are
1377 * no peers keep this quiet.
1378 * Also, if this was a remote event, no need to rebroadcast it.
1380 if( ( lpMsgHdr == NULL ) &&
1381 This->dp2->lpSessionDesc &&
1382 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1384 DPMSG_CREATEPLAYERORGROUP msg;
1385 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1387 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1388 msg.dpId = *lpidPlayer;
1389 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1390 msg.lpData = lpData;
1391 msg.dwDataSize = dwDataSize;
1392 msg.dpnName = *lpPlayerName;
1393 msg.dpIdParent = DPID_NOPARENT_GROUP;
1394 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1396 /* FIXME: Correct to just use send effectively? */
1397 /* FIXME: Should size include data w/ message or just message "header" */
1398 /* FIXME: Check return code */
1399 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1400 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1402 #endif
1404 return hr;
1407 static HRESULT WINAPI IDirectPlay4AImpl_CreatePlayer( IDirectPlay4A *iface, DPID *lpidPlayer,
1408 DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1410 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1412 if( lpidPlayer == NULL )
1414 return DPERR_INVALIDPARAMS;
1417 if( dwFlags & DPPLAYER_SERVERPLAYER )
1419 *lpidPlayer = DPID_SERVERPLAYER;
1421 else
1423 *lpidPlayer = DPID_UNKNOWN;
1426 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1427 lpData, dwDataSize, dwFlags, TRUE );
1430 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1431 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1432 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1434 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1436 if( lpidPlayer == NULL )
1438 return DPERR_INVALIDPARAMS;
1441 if( dwFlags & DPPLAYER_SERVERPLAYER )
1443 *lpidPlayer = DPID_SERVERPLAYER;
1445 else
1447 *lpidPlayer = DPID_UNKNOWN;
1450 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1451 lpData, dwDataSize, dwFlags, FALSE );
1454 static DPID DP_GetRemoteNextObjectId(void)
1456 FIXME( ":stub\n" );
1458 /* Hack solution */
1459 return DP_NextObjectId();
1462 static HRESULT DP_IF_DeletePlayerFromGroup
1463 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1464 DPID idPlayer, BOOL bAnsi )
1466 HRESULT hr = DP_OK;
1468 lpGroupData lpGData;
1469 lpPlayerList lpPList;
1471 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
1472 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1474 /* Find the group */
1475 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1477 return DPERR_INVALIDGROUP;
1480 /* Find the player */
1481 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1483 return DPERR_INVALIDPLAYER;
1486 /* Remove the player shortcut from the group */
1487 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1489 if( lpPList == NULL )
1491 return DPERR_INVALIDPLAYER;
1494 /* One less reference */
1495 lpPList->lpPData->uRef--;
1497 /* Delete the Player List element */
1498 HeapFree( GetProcessHeap(), 0, lpPList );
1500 /* Inform the SP if they care */
1501 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1503 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1505 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1507 data.idPlayer = idPlayer;
1508 data.idGroup = idGroup;
1509 data.lpISP = This->dp2->spData.lpISP;
1511 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1514 /* Need to send a DELETEPLAYERFROMGROUP message */
1515 FIXME( "Need to send a message\n" );
1517 return hr;
1520 static HRESULT WINAPI IDirectPlay4AImpl_DeletePlayerFromGroup( IDirectPlay4A *iface, DPID idGroup,
1521 DPID idPlayer )
1523 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1524 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1527 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1528 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1530 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1531 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1534 typedef struct _DPRGOPContext
1536 IDirectPlay3Impl* This;
1537 BOOL bAnsi;
1538 DPID idGroup;
1539 } DPRGOPContext, *lpDPRGOPContext;
1541 static BOOL CALLBACK
1542 cbRemoveGroupOrPlayer(
1543 DPID dpId,
1544 DWORD dwPlayerType,
1545 LPCDPNAME lpName,
1546 DWORD dwFlags,
1547 LPVOID lpContext )
1549 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1551 TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1552 dpId, dwPlayerType, lpCtxt->idGroup );
1554 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1556 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1557 dpId )
1561 ERR( "Unable to delete group 0x%08x from group 0x%08x\n",
1562 dpId, lpCtxt->idGroup );
1565 else
1567 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1568 NULL, lpCtxt->idGroup,
1569 dpId, lpCtxt->bAnsi )
1573 ERR( "Unable to delete player 0x%08x from grp 0x%08x\n",
1574 dpId, lpCtxt->idGroup );
1578 return TRUE; /* Continue enumeration */
1581 static HRESULT DP_IF_DestroyGroup
1582 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1584 lpGroupData lpGData;
1585 DPRGOPContext context;
1587 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1588 This, lpMsgHdr, idGroup, bAnsi );
1590 /* Find the group */
1591 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1593 return DPERR_INVALIDPLAYER; /* yes player */
1596 context.This = (IDirectPlay3Impl*)This;
1597 context.bAnsi = bAnsi;
1598 context.idGroup = idGroup;
1600 /* Remove all players that this group has */
1601 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1602 cbRemoveGroupOrPlayer, &context, 0, bAnsi );
1604 /* Remove all links to groups that this group has since this is dp3 */
1605 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1606 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1608 /* Remove this group from the parent group - if it has one */
1609 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1610 ( lpGData->parent != DPID_SYSTEM_GROUP )
1613 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1614 idGroup );
1617 /* Now delete this group data and list from the system group */
1618 DP_DeleteGroup( This, idGroup );
1620 /* Let the SP know that we've destroyed this group */
1621 if( This->dp2->spData.lpCB->DeleteGroup )
1623 DPSP_DELETEGROUPDATA data;
1625 FIXME( "data.dwFlags is incorrect\n" );
1627 data.idGroup = idGroup;
1628 data.dwFlags = 0;
1629 data.lpISP = This->dp2->spData.lpISP;
1631 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1634 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1636 return DP_OK;
1639 static HRESULT WINAPI IDirectPlay4AImpl_DestroyGroup( IDirectPlay4A *iface, DPID idGroup )
1641 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1642 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1645 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1646 ( LPDIRECTPLAY2 iface, DPID idGroup )
1648 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1649 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1652 typedef struct _DPFAGContext
1654 IDirectPlay2Impl* This;
1655 DPID idPlayer;
1656 BOOL bAnsi;
1657 } DPFAGContext, *lpDPFAGContext;
1659 static HRESULT DP_IF_DestroyPlayer
1660 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1662 DPFAGContext cbContext;
1664 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1665 This, lpMsgHdr, idPlayer, bAnsi );
1667 if( This->dp2->connectionInitialized == NO_PROVIDER )
1669 return DPERR_UNINITIALIZED;
1672 if( DP_FindPlayer( This, idPlayer ) == NULL )
1674 return DPERR_INVALIDPLAYER;
1677 /* FIXME: If the player is remote, we must be the host to delete this */
1679 cbContext.This = This;
1680 cbContext.idPlayer = idPlayer;
1681 cbContext.bAnsi = bAnsi;
1683 /* Find each group and call DeletePlayerFromGroup if the player is a
1684 member of the group */
1685 IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, NULL, cbDeletePlayerFromAllGroups, &cbContext,
1686 DPENUMGROUPS_ALL );
1688 /* Now delete player and player list from the sys group */
1689 DP_DeletePlayer( This, idPlayer );
1691 /* Let the SP know that we've destroyed this group */
1692 if( This->dp2->spData.lpCB->DeletePlayer )
1694 DPSP_DELETEPLAYERDATA data;
1696 FIXME( "data.dwFlags is incorrect\n" );
1698 data.idPlayer = idPlayer;
1699 data.dwFlags = 0;
1700 data.lpISP = This->dp2->spData.lpISP;
1702 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1705 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1707 return DP_OK;
1710 static BOOL CALLBACK
1711 cbDeletePlayerFromAllGroups(
1712 DPID dpId,
1713 DWORD dwPlayerType,
1714 LPCDPNAME lpName,
1715 DWORD dwFlags,
1716 LPVOID lpContext )
1718 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1720 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1722 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
1723 lpCtxt->bAnsi );
1725 /* Enumerate all groups in this group since this will normally only
1726 * be called for top level groups
1728 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
1729 dpId, NULL,
1730 cbDeletePlayerFromAllGroups,
1731 lpContext, DPENUMGROUPS_ALL,
1732 lpCtxt->bAnsi );
1735 else
1737 ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
1740 return TRUE;
1743 static HRESULT WINAPI IDirectPlay4AImpl_DestroyPlayer( IDirectPlay4A *iface, DPID idPlayer )
1745 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1746 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1749 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1750 ( LPDIRECTPLAY2 iface, DPID idPlayer )
1752 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1753 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1756 static HRESULT DP_IF_EnumGroupPlayers
1757 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1758 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1759 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1761 lpGroupData lpGData;
1762 lpPlayerList lpPList;
1764 FIXME("(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
1765 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1766 lpContext, dwFlags, bAnsi );
1768 if( This->dp2->connectionInitialized == NO_PROVIDER )
1770 return DPERR_UNINITIALIZED;
1773 /* Find the group */
1774 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1776 return DPERR_INVALIDGROUP;
1779 if( DPQ_IS_EMPTY( lpGData->players ) )
1781 return DP_OK;
1784 lpPList = DPQ_FIRST( lpGData->players );
1786 /* Walk the players in this group */
1787 for( ;; )
1789 /* We do not enum the name server or app server as they are of no
1790 * consequence to the end user.
1792 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
1793 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
1797 /* FIXME: Need to add stuff for dwFlags checking */
1799 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1800 &lpPList->lpPData->name,
1801 lpPList->lpPData->dwFlags,
1802 lpContext )
1805 /* User requested break */
1806 return DP_OK;
1810 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
1812 break;
1815 lpPList = DPQ_NEXT( lpPList->players );
1818 return DP_OK;
1821 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupPlayers( IDirectPlay4A *iface, DPID idGroup,
1822 GUID *lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1823 void *lpContext, DWORD dwFlags )
1825 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1826 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
1827 lpEnumPlayersCallback2, lpContext,
1828 dwFlags, TRUE );
1831 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
1832 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
1833 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1834 LPVOID lpContext, DWORD dwFlags )
1836 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1837 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
1838 lpEnumPlayersCallback2, lpContext,
1839 dwFlags, FALSE );
1842 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
1843 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroups( IDirectPlay4A *iface, GUID *instance,
1844 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1846 return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1847 context, flags );
1850 static HRESULT WINAPI IDirectPlay4Impl_EnumGroups ( IDirectPlay4 *iface, GUID *instance,
1851 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1853 return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1854 context, flags );
1857 static HRESULT WINAPI IDirectPlay4AImpl_EnumPlayers( IDirectPlay4A *iface, GUID *instance,
1858 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1860 return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1861 context, flags );
1864 static HRESULT WINAPI IDirectPlay4Impl_EnumPlayers( IDirectPlay4 *iface, GUID *instance,
1865 LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
1867 return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
1868 context, flags );
1871 /* This function should call the registered callback function that the user
1872 passed into EnumSessions for each entry available.
1874 static void DP_InvokeEnumSessionCallbacks
1875 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
1876 LPVOID lpNSInfo,
1877 DWORD dwTimeout,
1878 LPVOID lpContext )
1880 LPDPSESSIONDESC2 lpSessionDesc;
1882 FIXME( ": not checking for conditions\n" );
1884 /* Not sure if this should be pruning but it's convenient */
1885 NS_PruneSessionCache( lpNSInfo );
1887 NS_ResetSessionEnumeration( lpNSInfo );
1889 /* Enumerate all sessions */
1890 /* FIXME: Need to indicate ANSI */
1891 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
1893 TRACE( "EnumSessionsCallback2 invoked\n" );
1894 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
1896 return;
1900 /* Invoke one last time to indicate that there is no more to come */
1901 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
1904 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
1906 EnumSessionAsyncCallbackData* data = lpContext;
1907 HANDLE hSuicideRequest = data->hSuicideRequest;
1908 DWORD dwTimeout = data->dwTimeout;
1910 TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
1912 for( ;; )
1914 HRESULT hr;
1916 /* Sleep up to dwTimeout waiting for request to terminate thread */
1917 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
1919 TRACE( "Thread terminating on terminate request\n" );
1920 break;
1923 /* Now resend the enum request */
1924 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
1925 data->dwEnumSessionFlags,
1926 data->lpSpData );
1928 if( FAILED(hr) )
1930 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
1931 /* FIXME: Should we kill this thread? How to inform the main thread? */
1936 TRACE( "Thread terminating\n" );
1938 /* Clean up the thread data */
1939 CloseHandle( hSuicideRequest );
1940 HeapFree( GetProcessHeap(), 0, lpContext );
1942 /* FIXME: Need to have some notification to main app thread that this is
1943 * dead. It would serve two purposes. 1) allow sync on termination
1944 * so that we don't actually send something to ourselves when we
1945 * become name server (race condition) and 2) so that if we die
1946 * abnormally something else will be able to tell.
1949 return 1;
1952 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
1954 /* Does a thread exist? If so we were doing an async enum session */
1955 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
1957 TRACE( "Killing EnumSession thread %p\n",
1958 This->dp2->hEnumSessionThread );
1960 /* Request that the thread kill itself nicely */
1961 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
1962 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
1964 /* We no longer need to know about the thread */
1965 CloseHandle( This->dp2->hEnumSessionThread );
1967 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
1971 static HRESULT DP_IF_EnumSessions
1972 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
1973 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
1974 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1976 HRESULT hr = DP_OK;
1978 TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x,%u)\n",
1979 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
1980 bAnsi );
1981 if( This->dp2->connectionInitialized == NO_PROVIDER )
1983 return DPERR_UNINITIALIZED;
1986 /* Can't enumerate if the interface is already open */
1987 if( This->dp2->bConnectionOpen )
1989 return DPERR_GENERIC;
1992 #if 1
1993 /* The loading of a lobby provider _seems_ to require a backdoor loading
1994 * of the service provider to also associate with this DP object. This is
1995 * because the app doesn't seem to have to call EnumConnections and
1996 * InitializeConnection for the SP before calling this method. As such
1997 * we'll do their dirty work for them with a quick hack so as to always
1998 * load the TCP/IP service provider.
2000 * The correct solution would seem to involve creating a dialog box which
2001 * contains the possible SPs. These dialog boxes most likely follow SDK
2002 * examples.
2004 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2006 LPVOID lpConnection;
2007 DWORD dwSize;
2009 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2011 if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2013 ERR( "Can't build compound addr\n" );
2014 return DPERR_GENERIC;
2017 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2018 0, bAnsi );
2019 if( FAILED(hr) )
2021 return hr;
2024 /* Free up the address buffer */
2025 HeapFree( GetProcessHeap(), 0, lpConnection );
2027 /* The SP is now initialized */
2028 This->dp2->bSPInitialized = TRUE;
2030 #endif
2033 /* Use the service provider default? */
2034 if( dwTimeout == 0 )
2036 DPCAPS spCaps;
2037 spCaps.dwSize = sizeof( spCaps );
2039 DP_IF_GetCaps( This, &spCaps, 0 );
2040 dwTimeout = spCaps.dwTimeout;
2042 /* The service provider doesn't provide one either! */
2043 if( dwTimeout == 0 )
2045 /* Provide the TCP/IP default */
2046 dwTimeout = DPMSG_WAIT_5_SECS;
2050 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2052 DP_KillEnumSessionThread( This );
2053 return hr;
2056 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2058 /* Enumerate everything presently in the local session cache */
2059 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2060 This->dp2->lpNameServerData, dwTimeout,
2061 lpContext );
2063 if( This->dp2->dwEnumSessionLock != 0 )
2064 return DPERR_CONNECTING;
2066 /* See if we've already created a thread to service this interface */
2067 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2069 DWORD dwThreadId;
2070 This->dp2->dwEnumSessionLock++;
2072 /* Send the first enum request inline since the user may cancel a dialog
2073 * if one is presented. Also, may also have a connecting return code.
2075 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2076 dwFlags, &This->dp2->spData );
2078 if( SUCCEEDED(hr) )
2080 EnumSessionAsyncCallbackData* lpData
2081 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2082 /* FIXME: need to kill the thread on object deletion */
2083 lpData->lpSpData = &This->dp2->spData;
2085 lpData->requestGuid = lpsd->guidApplication;
2086 lpData->dwEnumSessionFlags = dwFlags;
2087 lpData->dwTimeout = dwTimeout;
2089 This->dp2->hKillEnumSessionThreadEvent =
2090 CreateEventW( NULL, TRUE, FALSE, NULL );
2092 if( !DuplicateHandle( GetCurrentProcess(),
2093 This->dp2->hKillEnumSessionThreadEvent,
2094 GetCurrentProcess(),
2095 &lpData->hSuicideRequest,
2096 0, FALSE, DUPLICATE_SAME_ACCESS )
2099 ERR( "Can't duplicate thread killing handle\n" );
2102 TRACE( ": creating EnumSessionsRequest thread\n" );
2104 This->dp2->hEnumSessionThread = CreateThread( NULL,
2106 DP_EnumSessionsSendAsyncRequestThread,
2107 lpData,
2109 &dwThreadId );
2111 This->dp2->dwEnumSessionLock--;
2114 else
2116 /* Invalidate the session cache for the interface */
2117 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2119 /* Send the broadcast for session enumeration */
2120 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2121 dwFlags,
2122 &This->dp2->spData );
2125 SleepEx( dwTimeout, FALSE );
2127 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2128 This->dp2->lpNameServerData, dwTimeout,
2129 lpContext );
2132 return hr;
2135 static HRESULT WINAPI IDirectPlay4AImpl_EnumSessions( IDirectPlay4A *iface, DPSESSIONDESC2 *lpsd,
2136 DWORD dwTimeout, LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2, void *lpContext,
2137 DWORD dwFlags )
2139 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2140 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2141 lpContext, dwFlags, TRUE );
2144 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2145 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2146 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2147 LPVOID lpContext, DWORD dwFlags )
2149 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2150 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2151 lpContext, dwFlags, FALSE );
2154 static HRESULT DP_IF_GetPlayerCaps
2155 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2156 DWORD dwFlags )
2158 DPSP_GETCAPSDATA data;
2160 TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
2162 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2164 return DPERR_UNINITIALIZED;
2167 /* Query the service provider */
2168 data.idPlayer = idPlayer;
2169 data.dwFlags = dwFlags;
2170 data.lpCaps = lpDPCaps;
2171 data.lpISP = This->dp2->spData.lpISP;
2173 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2176 static HRESULT DP_IF_GetCaps
2177 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2179 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2182 static HRESULT WINAPI IDirectPlay4AImpl_GetCaps( IDirectPlay4A *iface, DPCAPS *lpDPCaps,
2183 DWORD dwFlags )
2185 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2186 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2189 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2190 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2192 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2193 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2196 static HRESULT DP_IF_GetGroupData
2197 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2198 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2200 lpGroupData lpGData;
2201 DWORD dwRequiredBufferSize;
2202 LPVOID lpCopyDataFrom;
2204 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2205 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2207 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2209 return DPERR_INVALIDGROUP;
2212 /* How much buffer is required? */
2213 if( dwFlags & DPSET_LOCAL )
2215 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2216 lpCopyDataFrom = lpGData->lpLocalData;
2218 else
2220 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2221 lpCopyDataFrom = lpGData->lpRemoteData;
2224 /* Is the user requesting to know how big a buffer is required? */
2225 if( ( lpData == NULL ) ||
2226 ( *lpdwDataSize < dwRequiredBufferSize )
2229 *lpdwDataSize = dwRequiredBufferSize;
2230 return DPERR_BUFFERTOOSMALL;
2233 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2235 return DP_OK;
2238 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupData( IDirectPlay4A *iface, DPID idGroup,
2239 void *lpData, DWORD *lpdwDataSize, DWORD dwFlags )
2241 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2242 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2243 dwFlags, TRUE );
2246 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2247 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2248 LPDWORD lpdwDataSize, DWORD dwFlags )
2250 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2251 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2252 dwFlags, FALSE );
2255 static HRESULT DP_IF_GetGroupName
2256 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2257 LPDWORD lpdwDataSize, BOOL bAnsi )
2259 lpGroupData lpGData;
2260 LPDPNAME lpName = lpData;
2261 DWORD dwRequiredDataSize;
2263 FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2264 This, idGroup, lpData, lpdwDataSize, bAnsi );
2266 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2268 return DPERR_INVALIDGROUP;
2271 dwRequiredDataSize = lpGData->name.dwSize;
2273 if( lpGData->name.u1.lpszShortNameA )
2275 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2278 if( lpGData->name.u2.lpszLongNameA )
2280 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2283 if( ( lpData == NULL ) ||
2284 ( *lpdwDataSize < dwRequiredDataSize )
2287 *lpdwDataSize = dwRequiredDataSize;
2288 return DPERR_BUFFERTOOSMALL;
2291 /* Copy the structure */
2292 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2294 if( lpGData->name.u1.lpszShortNameA )
2296 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2297 lpGData->name.u1.lpszShortNameA );
2299 else
2301 lpName->u1.lpszShortNameA = NULL;
2304 if( lpGData->name.u1.lpszShortNameA )
2306 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2307 lpGData->name.u2.lpszLongNameA );
2309 else
2311 lpName->u2.lpszLongNameA = NULL;
2314 return DP_OK;
2317 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupName( IDirectPlay4A *iface, DPID idGroup,
2318 void *lpData, DWORD *lpdwDataSize )
2320 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2321 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2324 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2325 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2326 LPDWORD lpdwDataSize )
2328 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2329 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2332 static HRESULT WINAPI IDirectPlay4AImpl_GetMessageCount( IDirectPlay4A *iface, DPID player,
2333 DWORD *count )
2335 return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2338 static HRESULT WINAPI IDirectPlay4Impl_GetMessageCount( IDirectPlay4 *iface, DPID player,
2339 DWORD *count )
2341 return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2344 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAddress( IDirectPlay4A *iface, DPID player,
2345 void *data, DWORD *size )
2347 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2348 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2349 return DP_OK;
2352 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2353 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2355 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2356 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2357 return DP_OK;
2360 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerCaps( IDirectPlay4A *iface, DPID idPlayer,
2361 DPCAPS *lpPlayerCaps, DWORD dwFlags )
2363 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2364 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2367 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2368 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2369 DWORD dwFlags )
2371 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2372 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2375 static HRESULT DP_IF_GetPlayerData
2376 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2377 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2379 lpPlayerList lpPList;
2380 DWORD dwRequiredBufferSize;
2381 LPVOID lpCopyDataFrom;
2383 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2384 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2386 if( This->dp2->connectionInitialized == NO_PROVIDER )
2388 return DPERR_UNINITIALIZED;
2391 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2393 return DPERR_INVALIDPLAYER;
2396 /* How much buffer is required? */
2397 if( dwFlags & DPSET_LOCAL )
2399 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2400 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2402 else
2404 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2405 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2408 /* Is the user requesting to know how big a buffer is required? */
2409 if( ( lpData == NULL ) ||
2410 ( *lpdwDataSize < dwRequiredBufferSize )
2413 *lpdwDataSize = dwRequiredBufferSize;
2414 return DPERR_BUFFERTOOSMALL;
2417 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2419 return DP_OK;
2422 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerData( IDirectPlay4A *iface, DPID idPlayer,
2423 void *lpData, DWORD *lpdwDataSize, DWORD dwFlags )
2425 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2426 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2427 dwFlags, TRUE );
2430 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2431 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2432 LPDWORD lpdwDataSize, DWORD dwFlags )
2434 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2435 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2436 dwFlags, FALSE );
2439 static HRESULT DP_IF_GetPlayerName
2440 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2441 LPDWORD lpdwDataSize, BOOL bAnsi )
2443 lpPlayerList lpPList;
2444 LPDPNAME lpName = lpData;
2445 DWORD dwRequiredDataSize;
2447 FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2448 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2450 if( This->dp2->connectionInitialized == NO_PROVIDER )
2452 return DPERR_UNINITIALIZED;
2455 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2457 return DPERR_INVALIDPLAYER;
2460 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2462 if( lpPList->lpPData->name.u1.lpszShortNameA )
2464 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2467 if( lpPList->lpPData->name.u2.lpszLongNameA )
2469 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2472 if( ( lpData == NULL ) ||
2473 ( *lpdwDataSize < dwRequiredDataSize )
2476 *lpdwDataSize = dwRequiredDataSize;
2477 return DPERR_BUFFERTOOSMALL;
2480 /* Copy the structure */
2481 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2483 if( lpPList->lpPData->name.u1.lpszShortNameA )
2485 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2486 lpPList->lpPData->name.u1.lpszShortNameA );
2488 else
2490 lpName->u1.lpszShortNameA = NULL;
2493 if( lpPList->lpPData->name.u1.lpszShortNameA )
2495 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2496 lpPList->lpPData->name.u2.lpszLongNameA );
2498 else
2500 lpName->u2.lpszLongNameA = NULL;
2503 return DP_OK;
2506 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
2507 void *lpData, DWORD *lpdwDataSize )
2509 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2510 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2513 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2514 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2515 LPDWORD lpdwDataSize )
2517 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2518 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2521 static HRESULT DP_GetSessionDesc
2522 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2523 BOOL bAnsi )
2525 DWORD dwRequiredSize;
2527 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2529 if( This->dp2->connectionInitialized == NO_PROVIDER )
2531 return DPERR_UNINITIALIZED;
2534 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2536 return DPERR_INVALIDPARAMS;
2539 /* FIXME: Get from This->dp2->lpSessionDesc */
2540 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2542 if ( ( lpData == NULL ) ||
2543 ( *lpdwDataSize < dwRequiredSize )
2546 *lpdwDataSize = dwRequiredSize;
2547 return DPERR_BUFFERTOOSMALL;
2550 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2552 return DP_OK;
2555 static HRESULT WINAPI IDirectPlay4AImpl_GetSessionDesc( IDirectPlay4A *iface, void *lpData,
2556 DWORD *lpdwDataSize )
2558 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2559 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2562 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2563 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2565 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2566 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2569 /* Intended only for COM compatibility. Always returns an error. */
2570 static HRESULT WINAPI IDirectPlay4AImpl_Initialize( IDirectPlay4A *iface, GUID *guid )
2572 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2573 TRACE("(%p)->(%p): no-op\n", This, guid );
2574 return DPERR_ALREADYINITIALIZED;
2577 /* Intended only for COM compatibility. Always returns an error. */
2578 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2579 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2581 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2582 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2583 return DPERR_ALREADYINITIALIZED;
2587 static HRESULT DP_SecureOpen
2588 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2589 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2590 BOOL bAnsi )
2592 HRESULT hr = DP_OK;
2594 FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2595 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2597 if( This->dp2->connectionInitialized == NO_PROVIDER )
2599 return DPERR_UNINITIALIZED;
2602 if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
2604 TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
2605 return DPERR_INVALIDPARAMS;
2608 if( This->dp2->bConnectionOpen )
2610 TRACE( ": rejecting already open connection.\n" );
2611 return DPERR_ALREADYINITIALIZED;
2614 /* If we're enumerating, kill the thread */
2615 DP_KillEnumSessionThread( This );
2617 if( dwFlags & DPOPEN_CREATE )
2619 /* Rightoo - this computer is the host and the local computer needs to be
2620 the name server so that others can join this session */
2621 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2623 This->dp2->bHostInterface = TRUE;
2625 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2626 if( FAILED( hr ) )
2628 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2629 return hr;
2633 /* Invoke the conditional callback for the service provider */
2634 if( This->dp2->spData.lpCB->Open )
2636 DPSP_OPENDATA data;
2638 FIXME( "Not all data fields are correct. Need new parameter\n" );
2640 data.bCreate = (dwFlags & DPOPEN_CREATE ) != 0;
2641 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2642 : NS_GetNSAddr( This->dp2->lpNameServerData );
2643 data.lpISP = This->dp2->spData.lpISP;
2644 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) != 0;
2645 data.dwOpenFlags = dwFlags;
2646 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2648 hr = (*This->dp2->spData.lpCB->Open)(&data);
2649 if( FAILED( hr ) )
2651 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2652 return hr;
2657 /* Create the system group of which everything is a part of */
2658 DPID systemGroup = DPID_SYSTEM_GROUP;
2660 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2661 NULL, 0, 0, TRUE );
2665 if( dwFlags & DPOPEN_JOIN )
2667 DPID dpidServerId = DPID_UNKNOWN;
2669 /* Create the server player for this interface. This way we can receive
2670 * messages for this session.
2672 /* FIXME: I suppose that we should be setting an event for a receive
2673 * type of thing. That way the messaging thread could know to wake
2674 * up. DPlay would then trigger the hEvent for the player the
2675 * message is directed to.
2677 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2679 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2682 else if( dwFlags & DPOPEN_CREATE )
2684 DPID dpidNameServerId = DPID_NAME_SERVER;
2686 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2687 0, DPPLAYER_SERVERPLAYER, bAnsi );
2690 if( FAILED(hr) )
2692 ERR( "Couldn't create name server/system player: %s\n",
2693 DPLAYX_HresultToString(hr) );
2696 return hr;
2699 static HRESULT WINAPI IDirectPlay4AImpl_Open( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
2700 DWORD flags )
2702 return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
2705 static HRESULT WINAPI IDirectPlay4Impl_Open( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
2706 DWORD flags )
2708 return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
2711 static HRESULT DP_IF_Receive
2712 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2713 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2715 LPDPMSG lpMsg = NULL;
2717 FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
2718 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2720 if( This->dp2->connectionInitialized == NO_PROVIDER )
2722 return DPERR_UNINITIALIZED;
2725 if( dwFlags == 0 )
2727 dwFlags = DPRECEIVE_ALL;
2730 /* If the lpData is NULL, we must be peeking the message */
2731 if( ( lpData == NULL ) &&
2732 !( dwFlags & DPRECEIVE_PEEK )
2735 return DPERR_INVALIDPARAMS;
2738 if( dwFlags & DPRECEIVE_ALL )
2740 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2742 if( !( dwFlags & DPRECEIVE_PEEK ) )
2744 FIXME( "Remove from queue\n" );
2747 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2748 ( dwFlags & DPRECEIVE_FROMPLAYER )
2751 FIXME( "Find matching message 0x%08x\n", dwFlags );
2753 else
2755 ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
2758 if( lpMsg == NULL )
2760 return DPERR_NOMESSAGES;
2763 /* Copy into the provided buffer */
2764 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
2766 return DP_OK;
2769 static HRESULT WINAPI IDirectPlay4AImpl_Receive( IDirectPlay4A *iface, DPID *lpidFrom,
2770 DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
2772 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2773 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, TRUE );
2776 static HRESULT WINAPI DirectPlay2WImpl_Receive
2777 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
2778 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2780 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2781 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2782 lpData, lpdwDataSize, FALSE );
2785 static HRESULT WINAPI IDirectPlay4AImpl_Send( IDirectPlay4A *iface, DPID from, DPID to,
2786 DWORD flags, void *data, DWORD size )
2788 return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
2791 static HRESULT WINAPI IDirectPlay4Impl_Send( IDirectPlay4 *iface, DPID from, DPID to,
2792 DWORD flags, void *data, DWORD size )
2794 return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
2797 static HRESULT DP_IF_SetGroupData
2798 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2799 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
2801 lpGroupData lpGData;
2803 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
2804 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
2806 /* Parameter check */
2807 if( ( lpData == NULL ) &&
2808 ( dwDataSize != 0 )
2811 return DPERR_INVALIDPARAMS;
2814 /* Find the pointer to the data for this player */
2815 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2817 return DPERR_INVALIDOBJECT;
2820 if( !(dwFlags & DPSET_LOCAL) )
2822 FIXME( "Was this group created by this interface?\n" );
2823 /* FIXME: If this is a remote update need to allow it but not
2824 * send a message.
2828 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
2830 /* FIXME: Only send a message if this group is local to the session otherwise
2831 * it will have been rejected above
2833 if( !(dwFlags & DPSET_LOCAL) )
2835 FIXME( "Send msg?\n" );
2838 return DP_OK;
2841 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupData( IDirectPlay4A *iface, DPID idGroup,
2842 void *lpData, DWORD dwDataSize, DWORD dwFlags )
2844 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2845 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
2848 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
2849 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2850 DWORD dwDataSize, DWORD dwFlags )
2852 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2853 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
2856 static HRESULT DP_IF_SetGroupName
2857 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
2858 DWORD dwFlags, BOOL bAnsi )
2860 lpGroupData lpGData;
2862 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
2863 lpGroupName, dwFlags, bAnsi );
2865 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2867 return DPERR_INVALIDGROUP;
2870 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
2872 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
2873 FIXME( "Message not sent and dwFlags ignored\n" );
2875 return DP_OK;
2878 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupName( IDirectPlay4A *iface, DPID idGroup,
2879 DPNAME *lpGroupName, DWORD dwFlags )
2881 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2882 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
2885 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
2886 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
2887 DWORD dwFlags )
2889 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2890 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
2893 static HRESULT DP_IF_SetPlayerData
2894 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2895 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
2897 lpPlayerList lpPList;
2899 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
2900 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
2902 if( This->dp2->connectionInitialized == NO_PROVIDER )
2904 return DPERR_UNINITIALIZED;
2907 /* Parameter check */
2908 if( ( lpData == NULL ) &&
2909 ( dwDataSize != 0 )
2912 return DPERR_INVALIDPARAMS;
2915 /* Find the pointer to the data for this player */
2916 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2918 return DPERR_INVALIDPLAYER;
2921 if( !(dwFlags & DPSET_LOCAL) )
2923 FIXME( "Was this group created by this interface?\n" );
2924 /* FIXME: If this is a remote update need to allow it but not
2925 * send a message.
2929 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
2931 if( !(dwFlags & DPSET_LOCAL) )
2933 FIXME( "Send msg?\n" );
2936 return DP_OK;
2939 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerData( IDirectPlay4A *iface, DPID idPlayer,
2940 void *lpData, DWORD dwDataSize, DWORD dwFlags )
2942 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2943 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
2944 dwFlags, TRUE );
2947 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
2948 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2949 DWORD dwDataSize, DWORD dwFlags )
2951 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2952 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
2953 dwFlags, FALSE );
2956 static HRESULT DP_IF_SetPlayerName
2957 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
2958 DWORD dwFlags, BOOL bAnsi )
2960 lpPlayerList lpPList;
2962 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
2963 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
2965 if( This->dp2->connectionInitialized == NO_PROVIDER )
2967 return DPERR_UNINITIALIZED;
2970 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2972 return DPERR_INVALIDGROUP;
2975 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
2977 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
2978 FIXME( "Message not sent and dwFlags ignored\n" );
2980 return DP_OK;
2983 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
2984 DPNAME *lpPlayerName, DWORD dwFlags )
2986 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2987 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
2990 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
2991 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
2992 DWORD dwFlags )
2994 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2995 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
2998 static HRESULT DP_SetSessionDesc
2999 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3000 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3002 DWORD dwRequiredSize;
3003 LPDPSESSIONDESC2 lpTempSessDesc;
3005 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3006 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3008 if( This->dp2->connectionInitialized == NO_PROVIDER )
3010 return DPERR_UNINITIALIZED;
3013 if( dwFlags )
3015 return DPERR_INVALIDPARAMS;
3018 /* Only the host is allowed to update the session desc */
3019 if( !This->dp2->bHostInterface )
3021 return DPERR_ACCESSDENIED;
3024 /* FIXME: Copy into This->dp2->lpSessionDesc */
3025 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3026 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3028 if( lpTempSessDesc == NULL )
3030 return DPERR_OUTOFMEMORY;
3033 /* Free the old */
3034 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3036 This->dp2->lpSessionDesc = lpTempSessDesc;
3037 /* Set the new */
3038 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3039 if( bInitial )
3041 /*Initializing session GUID*/
3042 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3044 /* If this is an external invocation of the interface, we should be
3045 * letting everyone know that things have changed. Otherwise this is
3046 * just an initialization and it doesn't need to be propagated.
3048 if( !bInitial )
3050 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3053 return DP_OK;
3056 static HRESULT WINAPI IDirectPlay4AImpl_SetSessionDesc( IDirectPlay4A *iface,
3057 DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
3059 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3060 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3063 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3064 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3066 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3067 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3070 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3071 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3073 DWORD dwSize = 0;
3075 if( lpSessDesc == NULL )
3077 /* Hmmm..don't need any size? */
3078 ERR( "NULL lpSessDesc\n" );
3079 return dwSize;
3082 dwSize += sizeof( *lpSessDesc );
3084 if( bAnsi )
3086 if( lpSessDesc->u1.lpszSessionNameA )
3088 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3091 if( lpSessDesc->u2.lpszPasswordA )
3093 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3096 else /* UNICODE */
3098 if( lpSessDesc->u1.lpszSessionName )
3100 dwSize += sizeof( WCHAR ) *
3101 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3104 if( lpSessDesc->u2.lpszPassword )
3106 dwSize += sizeof( WCHAR ) *
3107 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3111 return dwSize;
3114 /* Assumes that contiguous buffers are already allocated. */
3115 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3116 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3118 BYTE* lpStartOfFreeSpace;
3120 if( lpSessionDest == NULL )
3122 ERR( "NULL lpSessionDest\n" );
3123 return;
3126 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3128 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3130 if( bAnsi )
3132 if( lpSessionSrc->u1.lpszSessionNameA )
3134 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3135 lpSessionDest->u1.lpszSessionNameA );
3136 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3137 lpStartOfFreeSpace +=
3138 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3141 if( lpSessionSrc->u2.lpszPasswordA )
3143 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3144 lpSessionDest->u2.lpszPasswordA );
3145 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3148 else /* UNICODE */
3150 if( lpSessionSrc->u1.lpszSessionName )
3152 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3153 lpSessionDest->u1.lpszSessionName );
3154 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3155 lpStartOfFreeSpace += sizeof(WCHAR) *
3156 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3159 if( lpSessionSrc->u2.lpszPassword )
3161 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3162 lpSessionDest->u2.lpszPassword );
3163 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3169 static HRESULT DP_IF_AddGroupToGroup
3170 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3172 lpGroupData lpGData;
3173 lpGroupList lpNewGList;
3175 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3177 if( This->dp2->connectionInitialized == NO_PROVIDER )
3179 return DPERR_UNINITIALIZED;
3182 if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3184 return DPERR_INVALIDGROUP;
3187 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3189 return DPERR_INVALIDGROUP;
3192 /* Create a player list (ie "shortcut" ) */
3193 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3194 if( lpNewGList == NULL )
3196 return DPERR_CANTADDPLAYER;
3199 /* Add the shortcut */
3200 lpGData->uRef++;
3201 lpNewGList->lpGData = lpGData;
3203 /* Add the player to the list of players for this group */
3204 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3206 /* Send a ADDGROUPTOGROUP message */
3207 FIXME( "Not sending message\n" );
3209 return DP_OK;
3212 static HRESULT WINAPI IDirectPlay4AImpl_AddGroupToGroup( IDirectPlay4A *iface, DPID idParentGroup,
3213 DPID idGroup )
3215 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3216 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3219 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3220 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3222 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3223 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3226 static HRESULT DP_IF_CreateGroupInGroup
3227 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3228 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3229 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3231 lpGroupData lpGParentData;
3232 lpGroupList lpGList;
3233 lpGroupData lpGData;
3235 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3236 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3237 dwDataSize, dwFlags, bAnsi );
3239 if( This->dp2->connectionInitialized == NO_PROVIDER )
3241 return DPERR_UNINITIALIZED;
3244 /* Verify that the specified parent is valid */
3245 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3246 idParentGroup ) ) == NULL
3249 return DPERR_INVALIDGROUP;
3252 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3253 dwFlags, idParentGroup, bAnsi );
3255 if( lpGData == NULL )
3257 return DPERR_CANTADDPLAYER; /* yes player not group */
3260 /* Something else is referencing this data */
3261 lpGData->uRef++;
3263 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3265 /* The list has now been inserted into the interface group list. We now
3266 need to put a "shortcut" to this group in the parent group */
3267 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3268 if( lpGList == NULL )
3270 FIXME( "Memory leak\n" );
3271 return DPERR_CANTADDPLAYER; /* yes player not group */
3274 lpGList->lpGData = lpGData;
3276 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3278 /* Let the SP know that we've created this group */
3279 if( This->dp2->spData.lpCB->CreateGroup )
3281 DPSP_CREATEGROUPDATA data;
3283 TRACE( "Calling SP CreateGroup\n" );
3285 data.idGroup = *lpidGroup;
3286 data.dwFlags = dwFlags;
3287 data.lpSPMessageHeader = lpMsgHdr;
3288 data.lpISP = This->dp2->spData.lpISP;
3290 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3293 /* Inform all other peers of the creation of a new group. If there are
3294 * no peers keep this quiet.
3296 if( This->dp2->lpSessionDesc &&
3297 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3299 DPMSG_CREATEPLAYERORGROUP msg;
3301 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3302 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3303 msg.dpId = *lpidGroup;
3304 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3305 msg.lpData = lpData;
3306 msg.dwDataSize = dwDataSize;
3307 msg.dpnName = *lpGroupName;
3309 /* FIXME: Correct to just use send effectively? */
3310 /* FIXME: Should size include data w/ message or just message "header" */
3311 /* FIXME: Check return code */
3312 DP_SendEx( (IDirectPlay2Impl*)This,
3313 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3314 0, 0, NULL, NULL, bAnsi );
3317 return DP_OK;
3320 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroupInGroup( IDirectPlay4A *iface,
3321 DPID idParentGroup, DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize,
3322 DWORD dwFlags )
3324 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3326 *lpidGroup = DPID_UNKNOWN;
3328 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
3329 dwDataSize, dwFlags, TRUE );
3332 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3333 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3334 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3335 DWORD dwFlags )
3337 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3339 *lpidGroup = DPID_UNKNOWN;
3341 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3342 lpGroupName, lpData, dwDataSize,
3343 dwFlags, FALSE );
3346 static HRESULT DP_IF_DeleteGroupFromGroup
3347 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3349 lpGroupList lpGList;
3350 lpGroupData lpGParentData;
3352 TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3354 /* Is the parent group valid? */
3355 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3357 return DPERR_INVALIDGROUP;
3360 /* Remove the group from the parent group queue */
3361 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3363 if( lpGList == NULL )
3365 return DPERR_INVALIDGROUP;
3368 /* Decrement the ref count */
3369 lpGList->lpGData->uRef--;
3371 /* Free up the list item */
3372 HeapFree( GetProcessHeap(), 0, lpGList );
3374 /* Should send a DELETEGROUPFROMGROUP message */
3375 FIXME( "message not sent\n" );
3377 return DP_OK;
3380 static HRESULT WINAPI IDirectPlay4AImpl_DeleteGroupFromGroup( IDirectPlay4A *iface,
3381 DPID idParentGroup, DPID idGroup )
3383 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3384 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3387 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3388 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3390 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3391 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3394 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3395 LPDWORD lpdwBufSize )
3397 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3398 HRESULT hr;
3400 dpCompoundAddress.dwDataSize = sizeof( GUID );
3401 dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3402 dpCompoundAddress.lpData = lpcSpGuid;
3404 *lplpAddrBuf = NULL;
3405 *lpdwBufSize = 0;
3407 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3408 lpdwBufSize, TRUE );
3410 if( hr != DPERR_BUFFERTOOSMALL )
3412 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3413 return FALSE;
3416 /* Now allocate the buffer */
3417 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3418 *lpdwBufSize );
3420 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3421 lpdwBufSize, TRUE );
3422 if( FAILED(hr) )
3424 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3425 return FALSE;
3428 return TRUE;
3431 static HRESULT WINAPI IDirectPlay4AImpl_EnumConnections( IDirectPlay4A *iface,
3432 const GUID *lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, void *lpContext,
3433 DWORD dwFlags )
3435 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3436 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3438 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3439 if( dwFlags == 0 )
3441 dwFlags = DPCONNECTION_DIRECTPLAY;
3444 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3445 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3448 return DPERR_INVALIDFLAGS;
3451 if( !lpEnumCallback )
3453 return DPERR_INVALIDPARAMS;
3456 /* Enumerate DirectPlay service providers */
3457 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3459 HKEY hkResult;
3460 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3461 LPCSTR guidDataSubKey = "Guid";
3462 char subKeyName[51];
3463 DWORD dwIndex, sizeOfSubKeyName=50;
3464 FILETIME filetime;
3466 /* Need to loop over the service providers in the registry */
3467 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3468 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3470 /* Hmmm. Does this mean that there are no service providers? */
3471 ERR(": no service providers?\n");
3472 return DP_OK;
3476 /* Traverse all the service providers we have available */
3477 for( dwIndex=0;
3478 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3479 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3480 ++dwIndex, sizeOfSubKeyName=51 )
3483 HKEY hkServiceProvider;
3484 GUID serviceProviderGUID;
3485 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3486 char returnBuffer[51];
3487 WCHAR buff[51];
3488 DPNAME dpName;
3489 BOOL bBuildPass;
3491 LPVOID lpAddressBuffer = NULL;
3492 DWORD dwAddressBufferSize = 0;
3494 TRACE(" this time through: %s\n", subKeyName );
3496 /* Get a handle for this particular service provider */
3497 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3498 &hkServiceProvider ) != ERROR_SUCCESS )
3500 ERR(": what the heck is going on?\n" );
3501 continue;
3504 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3505 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3506 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3508 ERR(": missing GUID registry data members\n" );
3509 RegCloseKey(hkServiceProvider);
3510 continue;
3512 RegCloseKey(hkServiceProvider);
3514 /* FIXME: Check return types to ensure we're interpreting data right */
3515 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3516 CLSIDFromString( buff, &serviceProviderGUID );
3517 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3519 /* Fill in the DPNAME struct for the service provider */
3520 dpName.dwSize = sizeof( dpName );
3521 dpName.dwFlags = 0;
3522 dpName.u1.lpszShortNameA = subKeyName;
3523 dpName.u2.lpszLongNameA = NULL;
3525 /* Create the compound address for the service provider.
3526 * NOTE: This is a gruesome architectural scar right now. DP
3527 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3528 * native dll just gets around this little bit by allocating an
3529 * 80 byte buffer which isn't even filled with a valid compound
3530 * address. Oh well. Creating a proper compound address is the
3531 * way to go anyways despite this method taking slightly more
3532 * heap space and realtime :) */
3534 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3535 &lpAddressBuffer,
3536 &dwAddressBufferSize );
3537 if( !bBuildPass )
3539 ERR( "Can't build compound addr\n" );
3540 return DPERR_GENERIC;
3543 /* The enumeration will return FALSE if we are not to continue */
3544 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3545 &dpName, dwFlags, lpContext ) )
3547 return DP_OK;
3552 /* Enumerate DirectPlayLobby service providers */
3553 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3555 HKEY hkResult;
3556 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3557 LPCSTR guidDataSubKey = "Guid";
3558 char subKeyName[51];
3559 DWORD dwIndex, sizeOfSubKeyName=50;
3560 FILETIME filetime;
3562 /* Need to loop over the service providers in the registry */
3563 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3564 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3566 /* Hmmm. Does this mean that there are no service providers? */
3567 ERR(": no service providers?\n");
3568 return DP_OK;
3572 /* Traverse all the lobby providers we have available */
3573 for( dwIndex=0;
3574 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3575 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3576 ++dwIndex, sizeOfSubKeyName=51 )
3579 HKEY hkServiceProvider;
3580 GUID serviceProviderGUID;
3581 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3582 char returnBuffer[51];
3583 WCHAR buff[51];
3584 DPNAME dpName;
3585 HRESULT hr;
3587 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3588 LPVOID lpAddressBuffer = NULL;
3589 DWORD dwAddressBufferSize = 0;
3591 TRACE(" this time through: %s\n", subKeyName );
3593 /* Get a handle for this particular service provider */
3594 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3595 &hkServiceProvider ) != ERROR_SUCCESS )
3597 ERR(": what the heck is going on?\n" );
3598 continue;
3601 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3602 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3603 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3605 ERR(": missing GUID registry data members\n" );
3606 RegCloseKey(hkServiceProvider);
3607 continue;
3609 RegCloseKey(hkServiceProvider);
3611 /* FIXME: Check return types to ensure we're interpreting data right */
3612 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3613 CLSIDFromString( buff, &serviceProviderGUID );
3614 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3616 /* Fill in the DPNAME struct for the service provider */
3617 dpName.dwSize = sizeof( dpName );
3618 dpName.dwFlags = 0;
3619 dpName.u1.lpszShortNameA = subKeyName;
3620 dpName.u2.lpszLongNameA = NULL;
3622 /* Create the compound address for the service provider.
3623 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3624 nast stuff. This may be why the native dll just gets around this little bit by
3625 allocating an 80 byte buffer which isn't even a filled with a valid compound
3626 address. Oh well. Creating a proper compound address is the way to go anyways
3627 despite this method taking slightly more heap space and realtime :) */
3629 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3630 dpCompoundAddress.dwDataSize = sizeof( GUID );
3631 dpCompoundAddress.lpData = &serviceProviderGUID;
3633 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3634 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3636 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3637 return hr;
3640 /* Now allocate the buffer */
3641 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3643 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3644 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3646 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3647 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3648 return hr;
3651 /* The enumeration will return FALSE if we are not to continue */
3652 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3653 &dpName, dwFlags, lpContext ) )
3655 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3656 return DP_OK;
3658 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3662 return DP_OK;
3665 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3666 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3668 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3669 FIXME("(%p)->(%p,%p,%p,0x%08x): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3670 return DP_OK;
3673 static HRESULT DP_IF_EnumGroupsInGroup
3674 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3675 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3676 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3678 lpGroupList lpGList;
3679 lpGroupData lpGData;
3681 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
3682 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3683 lpContext, dwFlags, bAnsi );
3685 if( This->dp2->connectionInitialized == NO_PROVIDER )
3687 return DPERR_UNINITIALIZED;
3690 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3692 return DPERR_INVALIDGROUP;
3695 if( DPQ_IS_EMPTY( lpGData->groups ) )
3697 return DP_OK;
3700 lpGList = DPQ_FIRST( lpGData->groups );
3702 for( ;; )
3704 /* FIXME: Should check dwFlags for match here */
3706 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3707 &lpGList->lpGData->name, dwFlags,
3708 lpContext ) )
3710 return DP_OK; /* User requested break */
3713 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3715 break;
3718 lpGList = DPQ_NEXT( lpGList->groups );
3722 return DP_OK;
3725 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupsInGroup( IDirectPlay4A *iface, DPID idGroup,
3726 GUID *lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, void *lpContext,
3727 DWORD dwFlags )
3729 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3730 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3731 lpEnumPlayersCallback2, lpContext, dwFlags,
3732 TRUE );
3735 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3736 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3737 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3738 DWORD dwFlags )
3740 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3741 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3742 lpEnumPlayersCallback2, lpContext, dwFlags,
3743 FALSE );
3746 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupConnectionSettings( IDirectPlay4A *iface,
3747 DWORD flags, DPID group, void *data, DWORD *size )
3749 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3750 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
3751 return DP_OK;
3754 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
3755 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3757 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3758 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3759 return DP_OK;
3762 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
3763 REFGUID guidDataType,
3764 DWORD dwDataSize,
3765 LPCVOID lpData,
3766 LPVOID lpContext )
3768 /* Looking for the GUID of the provider to load */
3769 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
3770 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
3773 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
3774 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
3776 if( dwDataSize != sizeof( GUID ) )
3778 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
3781 memcpy( lpContext, lpData, dwDataSize );
3783 /* There shouldn't be more than 1 GUID/compound address */
3784 return FALSE;
3787 /* Still waiting for what we want */
3788 return TRUE;
3792 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
3793 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
3795 UINT i;
3796 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3797 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3798 LPCSTR guidDataSubKey = "Guid";
3799 LPCSTR majVerDataSubKey = "dwReserved1";
3800 LPCSTR minVerDataSubKey = "dwReserved2";
3801 LPCSTR pathSubKey = "Path";
3803 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
3805 /* FIXME: Cloned code with a quick hack. */
3806 for( i=0; i<2; i++ )
3808 HKEY hkResult;
3809 LPCSTR searchSubKey;
3810 char subKeyName[51];
3811 DWORD dwIndex, sizeOfSubKeyName=50;
3812 FILETIME filetime;
3814 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
3815 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
3818 /* Need to loop over the service providers in the registry */
3819 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3820 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3822 /* Hmmm. Does this mean that there are no service providers? */
3823 ERR(": no service providers?\n");
3824 return 0;
3827 /* Traverse all the service providers we have available */
3828 for( dwIndex=0;
3829 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3830 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3831 ++dwIndex, sizeOfSubKeyName=51 )
3834 HKEY hkServiceProvider;
3835 GUID serviceProviderGUID;
3836 DWORD returnType, sizeOfReturnBuffer = 255;
3837 char returnBuffer[256];
3838 WCHAR buff[51];
3839 DWORD dwTemp, len;
3841 TRACE(" this time through: %s\n", subKeyName );
3843 /* Get a handle for this particular service provider */
3844 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3845 &hkServiceProvider ) != ERROR_SUCCESS )
3847 ERR(": what the heck is going on?\n" );
3848 continue;
3851 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3852 NULL, &returnType, (LPBYTE)returnBuffer,
3853 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3855 ERR(": missing GUID registry data members\n" );
3856 continue;
3859 /* FIXME: Check return types to ensure we're interpreting data right */
3860 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3861 CLSIDFromString( buff, &serviceProviderGUID );
3862 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3864 /* Determine if this is the Service Provider that the user asked for */
3865 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
3867 continue;
3870 if( i == 0 ) /* DP SP */
3872 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
3873 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
3874 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
3877 sizeOfReturnBuffer = 255;
3879 /* Get dwReserved1 */
3880 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
3881 NULL, &returnType, (LPBYTE)returnBuffer,
3882 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3884 ERR(": missing dwReserved1 registry data members\n") ;
3885 continue;
3888 if( i == 0 )
3889 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
3891 sizeOfReturnBuffer = 255;
3893 /* Get dwReserved2 */
3894 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
3895 NULL, &returnType, (LPBYTE)returnBuffer,
3896 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3898 ERR(": missing dwReserved1 registry data members\n") ;
3899 continue;
3902 if( i == 0 )
3903 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
3905 sizeOfReturnBuffer = 255;
3907 /* Get the path for this service provider */
3908 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
3909 NULL, NULL, (LPBYTE)returnBuffer,
3910 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
3912 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
3913 continue;
3916 TRACE( "Loading %s\n", returnBuffer );
3917 return LoadLibraryA( returnBuffer );
3921 return 0;
3924 static
3925 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
3927 HRESULT hr;
3928 LPDPSP_SPINIT SPInit;
3930 /* Initialize the service provider by calling SPInit */
3931 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
3933 if( SPInit == NULL )
3935 ERR( "Service provider doesn't provide SPInit interface?\n" );
3936 FreeLibrary( hServiceProvider );
3937 return DPERR_UNAVAILABLE;
3940 TRACE( "Calling SPInit (DP SP entry point)\n" );
3942 hr = (*SPInit)( &This->dp2->spData );
3944 if( FAILED(hr) )
3946 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
3947 FreeLibrary( hServiceProvider );
3948 return hr;
3951 /* FIXME: Need to verify the sanity of the returned callback table
3952 * using IsBadCodePtr */
3953 This->dp2->bSPInitialized = TRUE;
3955 /* This interface is now initialized as a DP object */
3956 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
3958 /* Store the handle of the module so that we can unload it later */
3959 This->dp2->hServiceProvider = hServiceProvider;
3961 return hr;
3964 static
3965 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
3967 HRESULT hr;
3968 LPSP_INIT DPLSPInit;
3970 /* Initialize the service provider by calling SPInit */
3971 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
3973 if( DPLSPInit == NULL )
3975 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
3976 FreeLibrary( hLobbyProvider );
3977 return DPERR_UNAVAILABLE;
3980 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
3982 hr = (*DPLSPInit)( &This->dp2->dplspData );
3984 if( FAILED(hr) )
3986 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
3987 FreeLibrary( hLobbyProvider );
3988 return hr;
3991 /* FIXME: Need to verify the sanity of the returned callback table
3992 * using IsBadCodePtr */
3994 This->dp2->bDPLSPInitialized = TRUE;
3996 /* This interface is now initialized as a lobby object */
3997 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
3999 /* Store the handle of the module so that we can unload it later */
4000 This->dp2->hDPLobbyProvider = hLobbyProvider;
4002 return hr;
4005 static HRESULT DP_IF_InitializeConnection
4006 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4008 HMODULE hServiceProvider;
4009 HRESULT hr;
4010 GUID guidSP;
4011 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4012 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4014 TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4016 if ( lpConnection == NULL )
4018 return DPERR_INVALIDPARAMS;
4021 if( dwFlags != 0 )
4023 return DPERR_INVALIDFLAGS;
4026 if( This->dp2->connectionInitialized != NO_PROVIDER )
4028 return DPERR_ALREADYINITIALIZED;
4031 /* Find out what the requested SP is and how large this buffer is */
4032 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4033 dwAddrSize, &guidSP );
4035 if( FAILED(hr) )
4037 ERR( "Invalid compound address?\n" );
4038 return DPERR_UNAVAILABLE;
4041 /* Load the service provider */
4042 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4044 if( hServiceProvider == 0 )
4046 ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4047 return DPERR_UNAVAILABLE;
4050 if( bIsDpSp )
4052 /* Fill in what we can of the Service Provider required information.
4053 * The rest was be done in DP_LoadSP
4055 This->dp2->spData.lpAddress = lpConnection;
4056 This->dp2->spData.dwAddressSize = dwAddrSize;
4057 This->dp2->spData.lpGuid = &guidSP;
4059 hr = DP_InitializeDPSP( This, hServiceProvider );
4061 else
4063 This->dp2->dplspData.lpAddress = lpConnection;
4065 hr = DP_InitializeDPLSP( This, hServiceProvider );
4068 if( FAILED(hr) )
4070 return hr;
4073 return DP_OK;
4076 static HRESULT WINAPI IDirectPlay4AImpl_InitializeConnection( IDirectPlay4A *iface,
4077 void *lpConnection, DWORD dwFlags )
4079 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4081 /* This may not be externally invoked once either an SP or LP is initialized */
4082 if( This->dp2->connectionInitialized != NO_PROVIDER )
4084 return DPERR_ALREADYINITIALIZED;
4087 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4090 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4091 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4093 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4095 /* This may not be externally invoked once either an SP or LP is initialized */
4096 if( This->dp2->connectionInitialized != NO_PROVIDER )
4098 return DPERR_ALREADYINITIALIZED;
4101 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4104 static HRESULT WINAPI IDirectPlay4AImpl_SecureOpen( IDirectPlay4A *iface,
4105 const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
4106 const DPCREDENTIALS *lpCredentials )
4108 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4109 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4112 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4113 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4114 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4116 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4117 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4120 static HRESULT WINAPI IDirectPlay4AImpl_SendChatMessage( IDirectPlay4A *iface, DPID from,
4121 DPID to, DWORD flags, DPCHAT *chatmsg )
4123 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4124 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
4125 return DP_OK;
4128 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4129 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4131 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4132 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4133 return DP_OK;
4136 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupConnectionSettings( IDirectPlay4A *iface,
4137 DWORD flags, DPID group, DPLCONNECTION *connection )
4139 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4140 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
4141 return DP_OK;
4144 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4145 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4147 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4148 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4149 return DP_OK;
4152 static HRESULT WINAPI IDirectPlay4AImpl_StartSession( IDirectPlay4A *iface, DWORD dwFlags,
4153 DPID idGroup )
4155 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4156 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4157 return DP_OK;
4160 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4161 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4163 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4164 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4165 return DP_OK;
4168 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupFlags( IDirectPlay4A *iface, DPID idGroup,
4169 DWORD *lpdwFlags )
4171 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4172 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4173 return DP_OK;
4176 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4177 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4179 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4180 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4181 return DP_OK;
4184 static HRESULT DP_IF_GetGroupParent
4185 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4186 BOOL bAnsi )
4188 lpGroupData lpGData;
4190 TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4192 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4194 return DPERR_INVALIDGROUP;
4197 *lpidGroup = lpGData->dpid;
4199 return DP_OK;
4202 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupParent( IDirectPlay4A *iface, DPID idGroup,
4203 DPID *lpidGroup )
4205 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4206 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4208 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4209 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4211 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4212 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4215 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAccount( IDirectPlay4A *iface, DPID player,
4216 DWORD flags, void *data, DWORD *size )
4218 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4219 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
4220 return DP_OK;
4223 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4224 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4226 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4227 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4228 return DP_OK;
4231 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerFlags( IDirectPlay4A *iface, DPID idPlayer,
4232 DWORD *lpdwFlags )
4234 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4235 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4236 return DP_OK;
4239 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4240 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4242 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4243 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4244 return DP_OK;
4247 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4248 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4250 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4251 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4252 return DP_OK;
4255 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4256 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4258 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4259 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4260 return DP_OK;
4263 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4264 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4266 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4267 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4268 return DP_OK;
4271 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4272 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4274 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4275 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4276 return DP_OK;
4279 static HRESULT DP_SendEx
4280 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4281 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4282 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4284 BOOL bValidDestination = FALSE;
4286 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4287 ": stub\n",
4288 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4289 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4291 if( This->dp2->connectionInitialized == NO_PROVIDER )
4293 return DPERR_UNINITIALIZED;
4296 /* FIXME: Add parameter checking */
4297 /* FIXME: First call to this needs to acquire a message id which will be
4298 * used for multiple sends
4301 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4303 /* Verify that the message is being sent from a valid local player. The
4304 * from player may be anonymous DPID_UNKNOWN
4306 if( idFrom != DPID_UNKNOWN )
4308 if( DP_FindPlayer( This, idFrom ) == NULL )
4310 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4311 return DPERR_INVALIDPLAYER;
4315 /* Verify that the message is being sent to a valid player, group or to
4316 * everyone. If it's valid, send it to those players.
4318 if( idTo == DPID_ALLPLAYERS )
4320 bValidDestination = TRUE;
4322 /* See if SP has the ability to multicast. If so, use it */
4323 if( This->dp2->spData.lpCB->SendToGroupEx )
4325 FIXME( "Use group sendex to group 0\n" );
4327 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4329 FIXME( "Use obsolete group send to group 0\n" );
4331 else /* No multicast, multiplicate */
4333 /* Send to all players we know about */
4334 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4338 if( ( !bValidDestination ) &&
4339 ( DP_FindPlayer( This, idTo ) != NULL )
4342 /* Have the service provider send this message */
4343 /* FIXME: Could optimize for local interface sends */
4344 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4345 dwTimeout, lpContext, lpdwMsgID );
4348 if( ( !bValidDestination ) &&
4349 ( DP_FindAnyGroup( This, idTo ) != NULL )
4352 bValidDestination = TRUE;
4354 /* See if SP has the ability to multicast. If so, use it */
4355 if( This->dp2->spData.lpCB->SendToGroupEx )
4357 FIXME( "Use group sendex\n" );
4359 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4361 FIXME( "Use obsolete group send to group\n" );
4363 else /* No multicast, multiplicate */
4365 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4368 #if 0
4369 if( bExpectReply )
4371 DWORD dwWaitReturn;
4373 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4375 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4376 if( dwWaitReturn != WAIT_OBJECT_0 )
4378 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4381 #endif
4384 if( !bValidDestination )
4386 return DPERR_INVALIDPLAYER;
4388 else
4390 /* FIXME: Should return what the send returned */
4391 return DP_OK;
4396 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4397 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4398 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4399 LPVOID lpContext, LPDWORD lpdwMsgID )
4401 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4402 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4403 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4406 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4407 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4408 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4409 LPVOID lpContext, LPDWORD lpdwMsgID )
4411 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4412 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4413 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4416 static HRESULT DP_SP_SendEx
4417 ( IDirectPlay2Impl* This, DWORD dwFlags,
4418 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4419 LPVOID lpContext, LPDWORD lpdwMsgID )
4421 LPDPMSG lpMElem;
4423 FIXME( ": stub\n" );
4425 /* FIXME: This queuing should only be for async messages */
4427 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4428 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4430 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4432 /* FIXME: Need to queue based on priority */
4433 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4435 return DP_OK;
4438 static HRESULT DP_IF_GetMessageQueue
4439 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4440 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4442 HRESULT hr = DP_OK;
4444 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4445 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4447 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4448 /* FIXME: What about sends which are not immediate? */
4450 if( This->dp2->spData.lpCB->GetMessageQueue )
4452 DPSP_GETMESSAGEQUEUEDATA data;
4454 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4456 /* FIXME: None of this is documented :( */
4458 data.lpISP = This->dp2->spData.lpISP;
4459 data.dwFlags = dwFlags;
4460 data.idFrom = idFrom;
4461 data.idTo = idTo;
4462 data.lpdwNumMsgs = lpdwNumMsgs;
4463 data.lpdwNumBytes = lpdwNumBytes;
4465 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4467 else
4469 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4472 return hr;
4475 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4476 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4477 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4479 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4480 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4481 lpdwNumBytes, TRUE );
4484 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4485 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4486 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4488 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4489 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4490 lpdwNumBytes, FALSE );
4493 static HRESULT DP_IF_CancelMessage
4494 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4495 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4497 HRESULT hr = DP_OK;
4499 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4500 This, dwMsgID, dwFlags, bAnsi );
4502 if( This->dp2->spData.lpCB->Cancel )
4504 DPSP_CANCELDATA data;
4506 TRACE( "Calling SP Cancel\n" );
4508 /* FIXME: Undocumented callback */
4510 data.lpISP = This->dp2->spData.lpISP;
4511 data.dwFlags = dwFlags;
4512 data.lprglpvSPMsgID = NULL;
4513 data.cSPMsgID = dwMsgID;
4514 data.dwMinPriority = dwMinPriority;
4515 data.dwMaxPriority = dwMaxPriority;
4517 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4519 else
4521 FIXME( "SP doesn't implement Cancel\n" );
4524 return hr;
4527 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4528 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4530 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4532 if( dwFlags != 0 )
4534 return DPERR_INVALIDFLAGS;
4537 if( dwMsgID == 0 )
4539 dwFlags |= DPCANCELSEND_ALL;
4542 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4545 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4546 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4548 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4550 if( dwFlags != 0 )
4552 return DPERR_INVALIDFLAGS;
4555 if( dwMsgID == 0 )
4557 dwFlags |= DPCANCELSEND_ALL;
4560 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4563 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4564 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4565 DWORD dwFlags )
4567 IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4569 if( dwFlags != 0 )
4571 return DPERR_INVALIDFLAGS;
4574 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4575 dwMaxPriority, TRUE );
4578 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4579 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4580 DWORD dwFlags )
4582 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4584 if( dwFlags != 0 )
4586 return DPERR_INVALIDFLAGS;
4589 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4590 dwMaxPriority, FALSE );
4593 /* Note: Hack so we can reuse the old functions without compiler warnings */
4594 # define XCAST(fun) (void*)
4595 static const IDirectPlay4Vtbl dp4_vt =
4597 IDirectPlay4Impl_QueryInterface,
4598 IDirectPlay4Impl_AddRef,
4599 IDirectPlay4Impl_Release,
4601 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
4602 XCAST(Close)DirectPlay2WImpl_Close,
4603 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
4604 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
4605 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
4606 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
4607 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
4608 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
4609 IDirectPlay4Impl_EnumGroups,
4610 IDirectPlay4Impl_EnumPlayers,
4611 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
4612 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
4613 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
4614 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
4615 IDirectPlay4Impl_GetMessageCount,
4616 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
4617 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
4618 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
4619 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
4620 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
4621 XCAST(Initialize)DirectPlay2WImpl_Initialize,
4622 IDirectPlay4Impl_Open,
4623 XCAST(Receive)DirectPlay2WImpl_Receive,
4624 IDirectPlay4Impl_Send,
4625 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
4626 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
4627 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
4628 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
4629 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
4631 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
4632 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
4633 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
4634 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
4635 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
4636 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
4637 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
4638 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
4639 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
4640 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
4641 XCAST(StartSession)DirectPlay3WImpl_StartSession,
4642 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
4643 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
4644 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
4645 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
4647 DirectPlay4WImpl_GetGroupOwner,
4648 DirectPlay4WImpl_SetGroupOwner,
4649 DirectPlay4WImpl_SendEx,
4650 DirectPlay4WImpl_GetMessageQueue,
4651 DirectPlay4WImpl_CancelMessage,
4652 DirectPlay4WImpl_CancelPriority
4654 #undef XCAST
4656 static const IDirectPlay4Vtbl dp4A_vt =
4658 IDirectPlay4AImpl_QueryInterface,
4659 IDirectPlay4AImpl_AddRef,
4660 IDirectPlay4AImpl_Release,
4661 IDirectPlay4AImpl_AddPlayerToGroup,
4662 IDirectPlay4AImpl_Close,
4663 IDirectPlay4AImpl_CreateGroup,
4664 IDirectPlay4AImpl_CreatePlayer,
4665 IDirectPlay4AImpl_DeletePlayerFromGroup,
4666 IDirectPlay4AImpl_DestroyGroup,
4667 IDirectPlay4AImpl_DestroyPlayer,
4668 IDirectPlay4AImpl_EnumGroupPlayers,
4669 IDirectPlay4AImpl_EnumGroups,
4670 IDirectPlay4AImpl_EnumPlayers,
4671 IDirectPlay4AImpl_EnumSessions,
4672 IDirectPlay4AImpl_GetCaps,
4673 IDirectPlay4AImpl_GetGroupData,
4674 IDirectPlay4AImpl_GetGroupName,
4675 IDirectPlay4AImpl_GetMessageCount,
4676 IDirectPlay4AImpl_GetPlayerAddress,
4677 IDirectPlay4AImpl_GetPlayerCaps,
4678 IDirectPlay4AImpl_GetPlayerData,
4679 IDirectPlay4AImpl_GetPlayerName,
4680 IDirectPlay4AImpl_GetSessionDesc,
4681 IDirectPlay4AImpl_Initialize,
4682 IDirectPlay4AImpl_Open,
4683 IDirectPlay4AImpl_Receive,
4684 IDirectPlay4AImpl_Send,
4685 IDirectPlay4AImpl_SetGroupData,
4686 IDirectPlay4AImpl_SetGroupName,
4687 IDirectPlay4AImpl_SetPlayerData,
4688 IDirectPlay4AImpl_SetPlayerName,
4689 IDirectPlay4AImpl_SetSessionDesc,
4690 IDirectPlay4AImpl_AddGroupToGroup,
4691 IDirectPlay4AImpl_CreateGroupInGroup,
4692 IDirectPlay4AImpl_DeleteGroupFromGroup,
4693 IDirectPlay4AImpl_EnumConnections,
4694 IDirectPlay4AImpl_EnumGroupsInGroup,
4695 IDirectPlay4AImpl_GetGroupConnectionSettings,
4696 IDirectPlay4AImpl_InitializeConnection,
4697 IDirectPlay4AImpl_SecureOpen,
4698 IDirectPlay4AImpl_SendChatMessage,
4699 IDirectPlay4AImpl_SetGroupConnectionSettings,
4700 IDirectPlay4AImpl_StartSession,
4701 IDirectPlay4AImpl_GetGroupFlags,
4702 IDirectPlay4AImpl_GetGroupParent,
4703 IDirectPlay4AImpl_GetPlayerAccount,
4704 IDirectPlay4AImpl_GetPlayerFlags,
4706 DirectPlay4AImpl_GetGroupOwner,
4707 DirectPlay4AImpl_SetGroupOwner,
4708 DirectPlay4AImpl_SendEx,
4709 DirectPlay4AImpl_GetMessageQueue,
4710 DirectPlay4AImpl_CancelMessage,
4711 DirectPlay4AImpl_CancelPriority
4714 HRESULT dplay_create( REFIID riid, void **ppv )
4716 IDirectPlayImpl *obj;
4717 HRESULT hr;
4719 TRACE( "(%s, %p)\n", debugstr_guid( riid ), ppv );
4721 *ppv = NULL;
4722 obj = HeapAlloc( GetProcessHeap(), 0, sizeof( *obj ) );
4723 if ( !obj )
4724 return DPERR_OUTOFMEMORY;
4726 obj->IDirectPlay4A_iface.lpVtbl = &dp4A_vt;
4727 obj->IDirectPlay4_iface.lpVtbl = &dp4_vt;
4728 obj->numIfaces = 1;
4729 obj->ref4A = 1;
4730 obj->ref4 = 0;
4732 InitializeCriticalSection( &obj->lock );
4733 obj->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlayImpl.lock");
4735 if ( DP_CreateDirectPlay2( obj ) )
4736 hr = IDirectPlayX_QueryInterface( &obj->IDirectPlay4A_iface, riid, ppv );
4737 else
4738 hr = DPERR_NOMEMORY;
4739 IDirectPlayX_Release( &obj->IDirectPlay4A_iface );
4741 return hr;
4745 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
4746 DPID idPlayer,
4747 LPVOID* lplpData )
4749 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
4751 if( lpPlayer == NULL )
4753 return DPERR_INVALIDPLAYER;
4756 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
4758 return DP_OK;
4761 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
4762 DPID idPlayer,
4763 LPVOID lpData )
4765 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
4767 if( lpPlayer == NULL )
4769 return DPERR_INVALIDPLAYER;
4772 lpPlayer->lpPData->lpSPPlayerData = lpData;
4774 return DP_OK;
4777 /***************************************************************************
4778 * DirectPlayEnumerateAW
4780 * The pointer to the structure lpContext will be filled with the
4781 * appropriate data for each service offered by the OS. These services are
4782 * not necessarily available on this particular machine but are defined
4783 * as simple service providers under the "Service Providers" registry key.
4784 * This structure is then passed to lpEnumCallback for each of the different
4785 * services.
4787 * This API is useful only for applications written using DirectX3 or
4788 * worse. It is superseded by IDirectPlay3::EnumConnections which also
4789 * gives information on the actual connections.
4791 * defn of a service provider:
4792 * A dynamic-link library used by DirectPlay to communicate over a network.
4793 * The service provider contains all the network-specific code required
4794 * to send and receive messages. Online services and network operators can
4795 * supply service providers to use specialized hardware, protocols, communications
4796 * media, and network resources.
4799 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
4800 LPDPENUMDPCALLBACKW lpEnumCallbackW,
4801 LPVOID lpContext)
4803 HKEY hkResult;
4804 static const WCHAR searchSubKey[] = {
4805 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
4806 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
4807 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
4808 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
4809 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
4810 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
4812 DWORD dwIndex;
4813 FILETIME filetime;
4815 char *descriptionA = NULL;
4816 DWORD max_sizeOfDescriptionA = 0;
4817 WCHAR *descriptionW = NULL;
4818 DWORD max_sizeOfDescriptionW = 0;
4820 if (!lpEnumCallbackA && !lpEnumCallbackW)
4822 return DPERR_INVALIDPARAMS;
4825 /* Need to loop over the service providers in the registry */
4826 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
4827 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
4829 /* Hmmm. Does this mean that there are no service providers? */
4830 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
4831 return DPERR_GENERIC;
4834 /* Traverse all the service providers we have available */
4835 dwIndex = 0;
4836 while (1)
4838 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
4839 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
4840 HKEY hkServiceProvider;
4841 GUID serviceProviderGUID;
4842 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
4843 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
4844 LONG ret_value;
4846 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4847 NULL, NULL, NULL, &filetime);
4848 if (ret_value == ERROR_NO_MORE_ITEMS)
4849 break;
4850 else if (ret_value != ERROR_SUCCESS)
4852 ERR(": could not enumerate on service provider key.\n");
4853 return DPERR_EXCEPTION;
4855 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
4857 /* Open the key for this service provider */
4858 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
4860 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
4861 continue;
4864 /* Get the GUID from the registry */
4865 if (RegQueryValueExW(hkServiceProvider, guidKey,
4866 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
4868 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
4869 continue;
4871 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
4873 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
4874 continue;
4876 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
4878 /* The enumeration will return FALSE if we are not to continue.
4880 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
4881 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
4882 * I think that it simply means that they are in-line with DirectX 6.0
4884 if (lpEnumCallbackA)
4886 DWORD sizeOfDescription = 0;
4888 /* Note that this is the A case of this function, so use the A variant to get the description string */
4889 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
4890 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
4892 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
4893 continue;
4895 if (sizeOfDescription > max_sizeOfDescriptionA)
4897 HeapFree(GetProcessHeap(), 0, descriptionA);
4898 max_sizeOfDescriptionA = sizeOfDescription;
4900 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
4901 RegQueryValueExA(hkServiceProvider, "DescriptionA",
4902 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
4904 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
4905 goto end;
4907 else
4909 DWORD sizeOfDescription = 0;
4911 if (RegQueryValueExW(hkServiceProvider, descW,
4912 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
4914 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
4915 continue;
4917 if (sizeOfDescription > max_sizeOfDescriptionW)
4919 HeapFree(GetProcessHeap(), 0, descriptionW);
4920 max_sizeOfDescriptionW = sizeOfDescription;
4922 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
4923 RegQueryValueExW(hkServiceProvider, descW,
4924 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
4926 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
4927 goto end;
4930 dwIndex++;
4933 end:
4934 HeapFree(GetProcessHeap(), 0, descriptionA);
4935 HeapFree(GetProcessHeap(), 0, descriptionW);
4937 return DP_OK;
4940 /***************************************************************************
4941 * DirectPlayEnumerate [DPLAYX.9]
4942 * DirectPlayEnumerateA [DPLAYX.2]
4944 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
4946 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
4948 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
4951 /***************************************************************************
4952 * DirectPlayEnumerateW [DPLAYX.3]
4954 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
4956 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
4958 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
4961 typedef struct tagCreateEnum
4963 LPVOID lpConn;
4964 LPCGUID lpGuid;
4965 } CreateEnumData, *lpCreateEnumData;
4967 /* Find and copy the matching connection for the SP guid */
4968 static BOOL CALLBACK cbDPCreateEnumConnections(
4969 LPCGUID lpguidSP,
4970 LPVOID lpConnection,
4971 DWORD dwConnectionSize,
4972 LPCDPNAME lpName,
4973 DWORD dwFlags,
4974 LPVOID lpContext)
4976 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
4978 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
4980 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
4982 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4983 dwConnectionSize );
4984 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
4986 /* Found the record that we were looking for */
4987 return FALSE;
4990 /* Haven't found what were looking for yet */
4991 return TRUE;
4995 /***************************************************************************
4996 * DirectPlayCreate [DPLAYX.1]
4999 HRESULT WINAPI DirectPlayCreate
5000 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5002 HRESULT hr;
5003 LPDIRECTPLAY3A lpDP3A;
5004 CreateEnumData cbData;
5006 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5008 if( pUnk != NULL )
5010 return CLASS_E_NOAGGREGATION;
5013 if( (lplpDP == NULL) || (lpGUID == NULL) )
5015 return DPERR_INVALIDPARAMS;
5018 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5019 give them an IDirectPlay2A object and hope that doesn't cause problems */
5020 if ( dplay_create( &IID_IDirectPlay2A, (void**)lplpDP ) != DP_OK )
5021 return DPERR_UNAVAILABLE;
5023 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5025 /* The GUID_NULL means don't bind a service provider. Just return the
5026 interface as is */
5027 return DP_OK;
5030 /* Bind the desired service provider since lpGUID is non NULL */
5031 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5033 /* We're going to use a DP3 interface */
5034 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5035 (LPVOID*)&lpDP3A );
5036 if( FAILED(hr) )
5038 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5039 return hr;
5042 cbData.lpConn = NULL;
5043 cbData.lpGuid = lpGUID;
5045 /* We were given a service provider, find info about it... */
5046 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5047 &cbData, DPCONNECTION_DIRECTPLAY );
5048 if( ( FAILED(hr) ) ||
5049 ( cbData.lpConn == NULL )
5052 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5053 IDirectPlayX_Release( lpDP3A );
5054 return DPERR_UNAVAILABLE;
5057 /* Initialize the service provider */
5058 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5059 if( FAILED(hr) )
5061 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5062 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5063 IDirectPlayX_Release( lpDP3A );
5064 return hr;
5067 /* Release our version of the interface now that we're done with it */
5068 IDirectPlayX_Release( lpDP3A );
5069 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5071 return DP_OK;