dplayx: Handling for "add forward" and "player enumeration" replies
[wine/gsoc_dplay.git] / dlls / dplayx / dplay.c
blob78f6fa7c7e381432ac910243d29e841400506f3a
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 #include "config.h"
21 #include "wine/port.h"
23 #include <stdarg.h>
24 #include <string.h>
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winerror.h"
30 #include "winbase.h"
31 #include "winnt.h"
32 #include "winreg.h"
33 #include "winnls.h"
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
37 #include "dpinit.h"
38 #include "dplayx_global.h"
39 #include "name_server.h"
40 #include "dplayx_queue.h"
41 #include "wine/dplaysp.h"
42 #include "dplay_global.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
46 /* FIXME: Should this be externed? */
47 extern HRESULT DPL_CreateCompoundAddress
48 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
49 LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
52 /* Local function prototypes */
53 static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
54 LPDPNAME lpName, DWORD dwFlags,
55 HANDLE hEvent, BOOL bAnsi );
56 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
57 static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
58 LPVOID lpData, DWORD dwDataSize );
60 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, const DPID *lpid,
61 const DPNAME *lpName, DWORD dwFlags,
62 DPID idParent, BOOL bAnsi );
63 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
64 LPVOID lpData, DWORD dwDataSize );
65 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
66 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
67 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
68 DWORD dwPlayerType,
69 LPCDPNAME lpName,
70 DWORD dwFlags,
71 LPVOID lpContext );
72 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
73 static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
74 LPCDPNAME lpName, DWORD dwFlags,
75 LPVOID lpContext );
76 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
78 /* Forward declarations of virtual tables */
79 static const IDirectPlay2Vtbl directPlay2AVT;
80 static const IDirectPlay3Vtbl directPlay3AVT;
81 static const IDirectPlay4Vtbl directPlay4AVT;
83 static const IDirectPlay2Vtbl directPlay2WVT;
84 static const IDirectPlay3Vtbl directPlay3WVT;
85 static const IDirectPlay4Vtbl directPlay4WVT;
87 /* Helper methods for player/group interfaces */
88 static HRESULT DP_IF_DeletePlayerFromGroup
89 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
90 DPID idPlayer, BOOL bAnsi );
91 static HRESULT DP_IF_CreatePlayer
92 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
93 LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
94 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
95 static HRESULT DP_IF_DestroyGroup
96 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
97 static HRESULT DP_IF_DestroyPlayer
98 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
99 static HRESULT DP_IF_EnumGroupPlayers
100 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
101 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
102 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
103 static HRESULT DP_IF_EnumGroups
104 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
105 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
106 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
107 static HRESULT DP_IF_EnumPlayers
108 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
109 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
110 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
111 static HRESULT DP_IF_GetGroupData
112 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
113 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
114 static HRESULT DP_IF_GetGroupName
115 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
116 LPDWORD lpdwDataSize, BOOL bAnsi );
117 static HRESULT DP_IF_GetPlayerData
118 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
119 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
120 static HRESULT DP_IF_GetPlayerName
121 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
122 LPDWORD lpdwDataSize, BOOL bAnsi );
123 static HRESULT DP_IF_SetGroupName
124 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
125 DWORD dwFlags, BOOL bAnsi );
126 static HRESULT DP_IF_SetPlayerData
127 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
128 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
129 static HRESULT DP_IF_SetPlayerName
130 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
131 DWORD dwFlags, BOOL bAnsi );
132 static HRESULT DP_IF_AddGroupToGroup
133 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
134 static HRESULT DP_IF_CreateGroup
135 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
136 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
137 DWORD dwFlags, BOOL bAnsi );
138 static HRESULT DP_IF_CreateGroupInGroup
139 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
140 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
141 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
142 static HRESULT DP_IF_AddPlayerToGroup
143 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
144 DPID idPlayer, BOOL bAnsi );
145 static HRESULT DP_IF_DeleteGroupFromGroup
146 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
147 static HRESULT DP_SetSessionDesc
148 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
149 DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
150 static HRESULT DP_SecureOpen
151 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
152 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
153 BOOL bAnsi );
154 static HRESULT DP_SendEx
155 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
156 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
157 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
158 static HRESULT DP_IF_Receive
159 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
160 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
161 static HRESULT DP_IF_GetMessageQueue
162 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
163 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
164 static HRESULT DP_SP_SendEx
165 ( IDirectPlay2Impl* This, DWORD dwFlags,
166 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
167 LPVOID lpContext, LPDWORD lpdwMsgID );
168 static HRESULT DP_IF_SetGroupData
169 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
170 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
171 static HRESULT DP_IF_GetPlayerCaps
172 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
173 DWORD dwFlags );
174 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
175 static HRESULT DP_IF_CancelMessage
176 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
177 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
178 static HRESULT DP_IF_EnumGroupsInGroup
179 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
180 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
181 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
182 static HRESULT DP_IF_GetGroupParent
183 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
184 BOOL bAnsi );
185 static HRESULT DP_IF_GetCaps
186 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
187 static HRESULT DP_IF_EnumSessions
188 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
189 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
190 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
191 static HRESULT DP_IF_InitializeConnection
192 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
193 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
194 LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
195 DWORD dwFlags, LPVOID lpContext );
196 static BOOL DP_BuildCompoundAddr( GUID guidDataType, LPGUID lpcSpGuid,
197 LPVOID* lplpAddrBuf, LPDWORD lpdwBufSize );
201 static inline DPID DP_NextObjectId(void);
202 static DPID DP_GetRemoteNextObjectId(void);
204 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
205 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
206 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
209 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
210 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
211 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
218 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
219 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
220 we don't have to change much */
221 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
223 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
224 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
226 /* Strip out all dwFlags values for CREATEPLAYER msg */
227 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
229 static LONG kludgePlayerGroupId = 1000;
231 /* ------------------------------------------------------------------ */
234 static BOOL DP_CreateIUnknown( LPVOID lpDP )
236 IDirectPlay2AImpl *This = lpDP;
238 This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
239 if ( This->unk == NULL )
241 return FALSE;
244 InitializeCriticalSection( &This->unk->DP_lock );
245 This->unk->DP_lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlay2AImpl*->DirectPlayIUnknownData*->DP_lock");
247 return TRUE;
250 static BOOL DP_DestroyIUnknown( LPVOID lpDP )
252 IDirectPlay2AImpl *This = lpDP;
254 This->unk->DP_lock.DebugInfo->Spare[0] = 0;
255 DeleteCriticalSection( &This->unk->DP_lock );
256 HeapFree( GetProcessHeap(), 0, This->unk );
258 return TRUE;
261 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
263 IDirectPlay2AImpl *This = lpDP;
265 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
266 if ( This->dp2 == NULL )
268 return FALSE;
271 This->dp2->bConnectionOpen = FALSE;
273 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
274 This->dp2->dwEnumSessionLock = 0;
276 This->dp2->bHostInterface = FALSE;
278 DPQ_INIT(This->dp2->receiveMsgs);
279 DPQ_INIT(This->dp2->sendMsgs);
280 DPQ_INIT(This->dp2->replysExpected);
282 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
284 /* FIXME: Memory leak */
285 return FALSE;
288 /* Provide an initial session desc with nothing in it */
289 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
290 HEAP_ZERO_MEMORY,
291 sizeof( *This->dp2->lpSessionDesc ) );
292 if( This->dp2->lpSessionDesc == NULL )
294 /* FIXME: Memory leak */
295 return FALSE;
297 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
299 /* We are emulating a dp 6 implementation */
300 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
302 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
303 sizeof( *This->dp2->spData.lpCB ) );
304 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
305 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
307 /* This is the pointer to the service provider */
308 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
309 (LPVOID*)&This->dp2->spData.lpISP, This ) )
312 /* FIXME: Memory leak */
313 return FALSE;
316 /* Setup lobby provider information */
317 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
318 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
319 sizeof( *This->dp2->dplspData.lpCB ) );
320 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
322 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
323 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
326 /* FIXME: Memory leak */
327 return FALSE;
330 return TRUE;
333 /* Definition of the global function in dplayx_queue.h. #
334 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
335 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
337 HeapFree( GetProcessHeap(), 0, elem );
340 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
342 IDirectPlay2AImpl *This = lpDP;
344 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
346 TerminateThread( This->dp2->hEnumSessionThread, 0 );
347 CloseHandle( This->dp2->hEnumSessionThread );
350 /* Finish with the SP - have it shutdown */
351 if( This->dp2->spData.lpCB->ShutdownEx )
353 DPSP_SHUTDOWNDATA data;
355 TRACE( "Calling SP ShutdownEx\n" );
357 data.lpISP = This->dp2->spData.lpISP;
359 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
361 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
363 TRACE( "Calling obsolete SP Shutdown\n" );
364 (*This->dp2->spData.lpCB->Shutdown)();
367 /* Unload the SP (if it exists) */
368 if( This->dp2->hServiceProvider != 0 )
370 FreeLibrary( This->dp2->hServiceProvider );
373 /* Unload the Lobby Provider (if it exists) */
374 if( This->dp2->hDPLobbyProvider != 0 )
376 FreeLibrary( This->dp2->hDPLobbyProvider );
379 /* FIXME: Need to delete receive and send msgs queue contents */
381 NS_DeleteSessionCache( This->dp2->lpNameServerData );
383 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
385 IDirectPlaySP_Release( This->dp2->spData.lpISP );
387 /* Delete the contents */
388 HeapFree( GetProcessHeap(), 0, This->dp2 );
390 return TRUE;
393 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
395 IDirectPlay3AImpl *This = lpDP;
397 This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
398 if ( This->dp3 == NULL )
400 return FALSE;
403 return TRUE;
406 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
408 IDirectPlay3AImpl *This = lpDP;
410 /* Delete the contents */
411 HeapFree( GetProcessHeap(), 0, This->dp3 );
413 return TRUE;
416 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
418 IDirectPlay4AImpl *This = lpDP;
420 This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
421 if ( This->dp4 == NULL )
423 return FALSE;
426 return TRUE;
429 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
431 IDirectPlay3AImpl *This = lpDP;
433 /* Delete the contents */
434 HeapFree( GetProcessHeap(), 0, This->dp4 );
436 return TRUE;
440 /* Create a new interface */
441 HRESULT DP_CreateInterface
442 ( REFIID riid, LPVOID* ppvObj )
444 TRACE( " for %s\n", debugstr_guid( riid ) );
446 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
447 sizeof( IDirectPlay2Impl ) );
449 if( *ppvObj == NULL )
451 return DPERR_OUTOFMEMORY;
454 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
456 IDirectPlay2Impl *This = *ppvObj;
457 This->lpVtbl = &directPlay2WVT;
459 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
461 IDirectPlay2AImpl *This = *ppvObj;
462 This->lpVtbl = &directPlay2AVT;
464 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
466 IDirectPlay3Impl *This = *ppvObj;
467 This->lpVtbl = &directPlay3WVT;
469 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
471 IDirectPlay3AImpl *This = *ppvObj;
472 This->lpVtbl = &directPlay3AVT;
474 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
476 IDirectPlay4Impl *This = *ppvObj;
477 This->lpVtbl = &directPlay4WVT;
479 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
481 IDirectPlay4AImpl *This = *ppvObj;
482 This->lpVtbl = &directPlay4AVT;
484 else
486 /* Unsupported interface */
487 HeapFree( GetProcessHeap(), 0, *ppvObj );
488 *ppvObj = NULL;
490 return E_NOINTERFACE;
493 /* Initialize it */
494 if ( DP_CreateIUnknown( *ppvObj ) &&
495 DP_CreateDirectPlay2( *ppvObj ) &&
496 DP_CreateDirectPlay3( *ppvObj ) &&
497 DP_CreateDirectPlay4( *ppvObj )
500 IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
502 return S_OK;
505 /* Initialize failed, destroy it */
506 DP_DestroyDirectPlay4( *ppvObj );
507 DP_DestroyDirectPlay3( *ppvObj );
508 DP_DestroyDirectPlay2( *ppvObj );
509 DP_DestroyIUnknown( *ppvObj );
511 HeapFree( GetProcessHeap(), 0, *ppvObj );
513 *ppvObj = NULL;
514 return DPERR_NOMEMORY;
518 /* Direct Play methods */
520 /* Shared between all dplay types */
521 static HRESULT WINAPI DP_QueryInterface
522 ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
524 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
525 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
527 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
528 sizeof( *This ) );
530 if( *ppvObj == NULL )
532 return DPERR_OUTOFMEMORY;
535 CopyMemory( *ppvObj, This, sizeof( *This ) );
536 (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
538 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
540 IDirectPlay2Impl *This = *ppvObj;
541 This->lpVtbl = &directPlay2WVT;
543 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
545 IDirectPlay2AImpl *This = *ppvObj;
546 This->lpVtbl = &directPlay2AVT;
548 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
550 IDirectPlay3Impl *This = *ppvObj;
551 This->lpVtbl = &directPlay3WVT;
553 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
555 IDirectPlay3AImpl *This = *ppvObj;
556 This->lpVtbl = &directPlay3AVT;
558 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
560 IDirectPlay4Impl *This = *ppvObj;
561 This->lpVtbl = &directPlay4WVT;
563 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
565 IDirectPlay4AImpl *This = *ppvObj;
566 This->lpVtbl = &directPlay4AVT;
568 else
570 /* Unsupported interface */
571 HeapFree( GetProcessHeap(), 0, *ppvObj );
572 *ppvObj = NULL;
574 return E_NOINTERFACE;
577 IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
579 return S_OK;
582 /* Shared between all dplay types */
583 static ULONG WINAPI DP_AddRef
584 ( LPDIRECTPLAY3 iface )
586 ULONG ulInterfaceRefCount, ulObjRefCount;
587 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
589 ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
590 ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
592 TRACE( "ref count incremented to %u:%u for %p\n",
593 ulInterfaceRefCount, ulObjRefCount, This );
595 return ulObjRefCount;
598 static ULONG WINAPI DP_Release
599 ( LPDIRECTPLAY3 iface )
601 ULONG ulInterfaceRefCount, ulObjRefCount;
603 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
605 ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
606 ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
608 TRACE( "ref count decremented to %u:%u for %p\n",
609 ulInterfaceRefCount, ulObjRefCount, This );
611 /* Deallocate if this is the last reference to the object */
612 if( ulObjRefCount == 0 )
614 /* If we're destroying the object, this must be the last ref
615 of the last interface */
616 DP_DestroyDirectPlay4( This );
617 DP_DestroyDirectPlay3( This );
618 DP_DestroyDirectPlay2( This );
619 DP_DestroyIUnknown( This );
622 /* Deallocate the interface */
623 if( ulInterfaceRefCount == 0 )
625 HeapFree( GetProcessHeap(), 0, This );
628 return ulObjRefCount;
631 static inline DPID DP_NextObjectId(void)
633 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
636 /* *lplpReply will be non NULL iff there is something to reply */
637 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
638 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
639 WORD wCommandId, WORD wVersion,
640 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
642 TRACE( "(%p)->(%p,0x%08x,%p,0x%x,%u)\n",
643 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
644 wVersion );
646 switch( wCommandId )
648 /* Name server needs to handle this request */
649 case DPMSGCMD_ENUMSESSIONS:
651 /* Reply expected */
652 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
654 break;
657 /* Name server needs to handle this request */
658 case DPMSGCMD_ENUMSESSIONSREPLY:
660 /* No reply expected */
661 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
662 This->dp2->spData.dwSPHeaderSize,
663 lpcMessageBody,
664 This->dp2->lpNameServerData );
665 break;
668 case DPMSGCMD_REQUESTPLAYERID:
670 LPDPSP_MSG_REQUESTPLAYERID lpcMsg = lpcMessageBody;
671 LPDPSP_MSG_REQUESTPLAYERREPLY lpReply;
673 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
675 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
677 lpReply = (LPDPSP_MSG_REQUESTPLAYERREPLY)( (LPBYTE)(*lplpReply) +
678 This->dp2->spData.dwSPHeaderSize );
680 lpReply->envelope.dwMagic = DPMSG_SIGNATURE;
681 lpReply->envelope.wCommandId = DPMSGCMD_REQUESTPLAYERREPLY;
682 lpReply->envelope.wVersion = DX61AVERSION;
684 if ( lpcMsg->Flags & DPLAYI_PLAYER_SYSPLAYER )
686 /* Request to join the game */
688 if ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_SECURESERVER )
690 FIXME( "Fill lpReply->SecDesc with Game->SSPIProvider\n" );
692 FIXME( "Fill lpReply->CAPIProvider with Game->CAPIProvider\n" );
693 FIXME( "Fill lpReply->SecDesc->dwEncryptionAlgorithm with Game->EncryptionAlgorithm\n" );
695 /* Player is not local anymore */
696 lpcMsg->Flags ^= DPLAYI_PLAYER_PLAYERLOCAL;
698 lpReply->ID = DP_NextObjectId();
699 lpReply->Result = DP_IF_CreatePlayer( This, lpcMessageHeader,
700 &lpReply->ID, NULL, 0, NULL, 0,
701 lpcMsg->Flags, TRUE/*TODO*/ );
702 lpReply->Result = S_OK;
704 else
706 /* Request to to add a normal player from an
707 * existing member of the session */
709 if ( ( This->dp2->lpSessionDesc->dwCurrentPlayers
710 == This->dp2->lpSessionDesc->dwMaxPlayers ) ||
711 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_NEWPLAYERSDISABLED ) )
713 lpReply->Result = DPERR_NONEWPLAYERS;
715 else
717 lpReply->ID = DP_NextObjectId();
718 lpReply->Result = S_OK;
722 break;
725 case DPMSGCMD_PACKET:
727 LPCDPSP_MSG_PACKET lpcMsg = lpcMessageBody;
728 LPDPSP_MSG_ENVELOPE packetData;
730 /* TODO: We have to wait for all the messages in the sequence and
731 * assemble them in a bigger message. */
732 if ( lpcMsg->TotalPackets > 1 )
734 FIXME( "TODO: Message belongs to a sequence of %d, implement assembly\n",
735 lpcMsg->TotalPackets );
736 return DPERR_GENERIC;
739 /* For now, for simplicity we'll just decapsulate the embedded
740 * message and work with it. */
741 packetData = (LPVOID)(lpcMsg + 1);
743 TRACE( "Processing embedded message with envelope (0x%08x, 0x%08x, %d)\n",
744 packetData->dwMagic, packetData->wCommandId, packetData->wVersion );
746 return DP_HandleMessage( This,
747 packetData,
748 lpcMsg->DataSize,
749 lpcMessageHeader,
750 packetData->wCommandId,
751 packetData->wVersion,
752 lplpReply, lpdwMsgSize );
753 break;
756 case DPMSGCMD_REQUESTPLAYERREPLY:
758 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageHeader,
759 lpcMessageBody, dwMessageBodySize );
760 break;
763 case DPMSGCMD_ADDFORWARDREQUEST:
765 /*LPCDPSP_MSG_ADDFORWARDREQUEST lpcMsg =
766 (LPCDPSP_MSG_ADDFORWARDREQUEST) lpcMessageBody;*/
768 /* TODO: Send ADDFORWARD messages to all the players to populate
769 * their name tables.
770 * Start NametablePopulation timer and wait for ADDFORWARDACKs */
771 FIXME( "Spread name table population messages\n" );
773 /* TODO remember to set local addr somewhere */
774 /* call NS_SetLocalAddr with a SOCKADDR_IN */
776 FIXME( "This should happen after we received all the DPMSGCMD_ADDFORWARDACKs\n" );
777 DP_MSG_ReplyToEnumPlayersRequest( This, lplpReply, lpdwMsgSize );
779 break;
782 case DPMSGCMD_ADDFORWARDREPLY:
784 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageHeader,
785 lpcMessageBody, dwMessageBodySize );
786 break;
789 case DPMSGCMD_ENUMPLAYERSREPLY:
790 case DPMSGCMD_SUPERENUMPLAYERSREPLY:
792 /* If we're joining a session, when we receive this
793 * command we were waiting for a ADDFORWARDREPLY */
794 if ( !DP_MSG_ReplyReceived( This, DPMSGCMD_ADDFORWARDREPLY,
795 lpcMessageHeader, lpcMessageBody,
796 dwMessageBodySize ) )
798 /* If we were not joining a session, check if we are
799 * waiting for an enumeration of players or groups */
800 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageHeader,
801 lpcMessageBody, dwMessageBodySize );
803 break;
806 case DPMSGCMD_ADDFORWARDACK:
808 /* When we receive an ADDFORWARDACK for each of the ADDFORWARDs
809 * we've sent, send a SUPERENUMPLAYERSREPLY back to the peer
810 * that sent the ADDFORWARDREQUEST */
811 /* TODO: We'll skip this for now and just send the SUPERENUMPLAYERSREPLY
812 * right away when we get a ADDFORWARDREQUEST */
813 break;
816 default:
818 FIXME( "Unknown wCommandId 0x%08x. Ignoring message\n", wCommandId );
819 return DPERR_GENERIC;
823 return DP_OK;
827 static HRESULT DP_IF_AddPlayerToGroup
828 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
829 DPID idPlayer, BOOL bAnsi )
831 lpGroupData lpGData;
832 lpPlayerList lpPList;
833 lpPlayerList lpNewPList;
835 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
836 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
838 if( This->dp2->connectionInitialized == NO_PROVIDER )
840 return DPERR_UNINITIALIZED;
843 /* Find the group */
844 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
846 return DPERR_INVALIDGROUP;
849 /* Find the player */
850 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
852 return DPERR_INVALIDPLAYER;
855 /* Create a player list (ie "shortcut" ) */
856 lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
857 if( lpNewPList == NULL )
859 return DPERR_CANTADDPLAYER;
862 /* Add the shortcut */
863 lpPList->lpPData->uRef++;
864 lpNewPList->lpPData = lpPList->lpPData;
866 /* Add the player to the list of players for this group */
867 DPQ_INSERT(lpGData->players,lpNewPList,players);
869 /* Let the SP know that we've added a player to the group */
870 if( This->dp2->spData.lpCB->AddPlayerToGroup )
872 DPSP_ADDPLAYERTOGROUPDATA data;
874 TRACE( "Calling SP AddPlayerToGroup\n" );
876 data.idPlayer = idPlayer;
877 data.idGroup = idGroup;
878 data.lpISP = This->dp2->spData.lpISP;
880 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
883 /* Inform all other peers of the addition of player to the group. If there are
884 * no peers keep this event quiet.
885 * Also, if this event was the result of another machine sending it to us,
886 * don't bother rebroadcasting it.
888 if( ( lpMsgHdr == NULL ) &&
889 This->dp2->lpSessionDesc &&
890 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
892 DPMSG_ADDPLAYERTOGROUP msg;
893 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
895 msg.dpIdGroup = idGroup;
896 msg.dpIdPlayer = idPlayer;
898 /* FIXME: Correct to just use send effectively? */
899 /* FIXME: Should size include data w/ message or just message "header" */
900 /* FIXME: Check return code */
901 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
904 return DP_OK;
907 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
908 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
910 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
911 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
914 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
915 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
917 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
918 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
921 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
923 HRESULT hr = DP_OK;
925 TRACE("(%p)->(%u)\n", This, bAnsi );
927 /* FIXME: Need to find a new host I assume (how?) */
928 /* FIXME: Need to destroy all local groups */
929 /* FIXME: Need to migrate all remotely visible players to the new host */
931 /* Invoke the SP callback to inform of session close */
932 if( This->dp2->spData.lpCB->CloseEx )
934 DPSP_CLOSEDATA data;
936 TRACE( "Calling SP CloseEx\n" );
938 data.lpISP = This->dp2->spData.lpISP;
940 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
943 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
945 TRACE( "Calling SP Close (obsolete interface)\n" );
947 hr = (*This->dp2->spData.lpCB->Close)();
950 if ( !FAILED(hr) )
952 This->dp2->bConnectionOpen = FALSE;
955 return hr;
958 static HRESULT WINAPI DirectPlay2AImpl_Close
959 ( LPDIRECTPLAY2A iface )
961 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
962 return DP_IF_Close( This, TRUE );
965 static HRESULT WINAPI DirectPlay2WImpl_Close
966 ( LPDIRECTPLAY2 iface )
968 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
969 return DP_IF_Close( This, FALSE );
972 static
973 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
974 const DPNAME *lpName, DWORD dwFlags,
975 DPID idParent, BOOL bAnsi )
977 lpGroupData lpGData;
979 /* Allocate the new space and add to end of high level group list */
980 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
982 if( lpGData == NULL )
984 return NULL;
987 DPQ_INIT(lpGData->groups);
988 DPQ_INIT(lpGData->players);
990 /* Set the desired player ID - no sanity checking to see if it exists */
991 lpGData->dpid = *lpid;
993 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
995 /* FIXME: Should we check that the parent exists? */
996 lpGData->parent = idParent;
998 /* FIXME: Should we validate the dwFlags? */
999 lpGData->dwFlags = dwFlags;
1001 TRACE( "Created group id 0x%08x\n", *lpid );
1003 return lpGData;
1006 /* This method assumes that all links to it are already deleted */
1007 static void
1008 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
1010 lpGroupList lpGList;
1012 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1014 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
1016 if( lpGList == NULL )
1018 ERR( "DPID 0x%08x not found\n", dpid );
1019 return;
1022 if( --(lpGList->lpGData->uRef) )
1024 FIXME( "Why is this not the last reference to group?\n" );
1025 DebugBreak();
1028 /* Delete player */
1029 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
1030 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
1032 /* Remove and Delete Player List object */
1033 HeapFree( GetProcessHeap(), 0, lpGList );
1037 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
1039 lpGroupList lpGroups;
1041 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1043 if( dpid == DPID_SYSTEM_GROUP )
1045 return This->dp2->lpSysGroup;
1047 else
1049 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
1052 if( lpGroups == NULL )
1054 return NULL;
1057 return lpGroups->lpGData;
1060 static HRESULT DP_IF_CreateGroup
1061 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
1062 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
1063 DWORD dwFlags, BOOL bAnsi )
1065 lpGroupData lpGData;
1067 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1068 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
1069 dwFlags, bAnsi );
1071 /* If the name is not specified, we must provide one */
1072 if( DPID_UNKNOWN == *lpidGroup )
1074 /* If we are the name server, we decide on the group ids. If not, we
1075 * must ask for one before attempting a creation.
1077 if( This->dp2->bHostInterface )
1079 *lpidGroup = DP_NextObjectId();
1081 else
1083 *lpidGroup = DP_GetRemoteNextObjectId();
1087 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1088 DPID_NOPARENT_GROUP, bAnsi );
1090 if( lpGData == NULL )
1092 return DPERR_CANTADDPLAYER; /* yes player not group */
1095 if( DPID_SYSTEM_GROUP == *lpidGroup )
1097 This->dp2->lpSysGroup = lpGData;
1098 TRACE( "Inserting system group\n" );
1100 else
1102 /* Insert into the system group */
1103 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1104 lpGroup->lpGData = lpGData;
1106 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1109 /* Something is now referencing this data */
1110 lpGData->uRef++;
1112 /* Set all the important stuff for the group */
1113 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1115 /* FIXME: We should only create the system group if GetCaps returns
1116 * DPCAPS_GROUPOPTIMIZED.
1119 /* Let the SP know that we've created this group */
1120 if( This->dp2->spData.lpCB->CreateGroup )
1122 DPSP_CREATEGROUPDATA data;
1123 DWORD dwCreateFlags = 0;
1125 TRACE( "Calling SP CreateGroup\n" );
1127 if( *lpidGroup == DPID_NOPARENT_GROUP )
1128 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1130 if( lpMsgHdr == NULL )
1131 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1133 if( dwFlags & DPGROUP_HIDDEN )
1134 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1136 data.idGroup = *lpidGroup;
1137 data.dwFlags = dwCreateFlags;
1138 data.lpSPMessageHeader = lpMsgHdr;
1139 data.lpISP = This->dp2->spData.lpISP;
1141 (*This->dp2->spData.lpCB->CreateGroup)( &data );
1144 /* Inform all other peers of the creation of a new group. If there are
1145 * no peers keep this event quiet.
1146 * Also if this message was sent to us, don't rebroadcast.
1148 if( ( lpMsgHdr == NULL ) &&
1149 This->dp2->lpSessionDesc &&
1150 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1152 DPMSG_CREATEPLAYERORGROUP msg;
1153 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1155 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
1156 msg.dpId = *lpidGroup;
1157 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1158 msg.lpData = lpData;
1159 msg.dwDataSize = dwDataSize;
1160 msg.dpnName = *lpGroupName;
1161 msg.dpIdParent = DPID_NOPARENT_GROUP;
1162 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1164 /* FIXME: Correct to just use send effectively? */
1165 /* FIXME: Should size include data w/ message or just message "header" */
1166 /* FIXME: Check return code */
1167 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
1168 0, 0, NULL, NULL, bAnsi );
1171 return DP_OK;
1174 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
1175 ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1176 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1178 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1180 if( This->dp2->connectionInitialized == NO_PROVIDER )
1182 return DPERR_UNINITIALIZED;
1185 if( lpidGroup == NULL ||
1186 !This->dp2->bConnectionOpen ||
1187 dwDataSize >= MAXDWORD ||
1188 ( lpData == NULL && dwDataSize != 0 ) )
1190 return DPERR_INVALIDPARAMS;
1193 *lpidGroup = DPID_UNKNOWN;
1195 return DP_IF_CreateGroup( This, NULL, lpidGroup,
1196 lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
1199 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1200 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1201 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1203 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1205 if( This->dp2->connectionInitialized == NO_PROVIDER )
1207 return DPERR_UNINITIALIZED;
1210 if( lpidGroup == NULL ||
1211 !This->dp2->bConnectionOpen ||
1212 dwDataSize >= MAXDWORD ||
1213 ( lpData == NULL && dwDataSize != 0 ) )
1215 return DPERR_INVALIDPARAMS;
1218 *lpidGroup = DPID_UNKNOWN;
1220 return DP_IF_CreateGroup( This, NULL, lpidGroup,
1221 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
1225 static void
1226 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1227 LPVOID lpData, DWORD dwDataSize )
1229 /* Clear out the data with this player */
1230 if( dwFlags & DPSET_LOCAL )
1232 if ( lpGData->dwLocalDataSize != 0 )
1234 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1235 lpGData->lpLocalData = NULL;
1236 lpGData->dwLocalDataSize = 0;
1239 else
1241 if( lpGData->dwRemoteDataSize != 0 )
1243 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1244 lpGData->lpRemoteData = NULL;
1245 lpGData->dwRemoteDataSize = 0;
1249 /* Reallocate for new data */
1250 if( lpData != NULL )
1252 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1253 sizeof( dwDataSize ) );
1254 CopyMemory( lpNewData, lpData, dwDataSize );
1256 if( dwFlags & DPSET_LOCAL )
1258 lpGData->lpLocalData = lpData;
1259 lpGData->dwLocalDataSize = dwDataSize;
1261 else
1263 lpGData->lpRemoteData = lpNewData;
1264 lpGData->dwRemoteDataSize = dwDataSize;
1270 /* This function will just create the storage for the new player. */
1271 static
1272 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1273 LPDPNAME lpName, DWORD dwFlags,
1274 HANDLE hEvent, BOOL bAnsi )
1276 lpPlayerData lpPData;
1278 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1280 /* Allocate the storage for the player and associate it with list element */
1281 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1282 if( lpPData == NULL )
1284 return NULL;
1287 /* Set the desired player ID */
1288 lpPData->dpid = *lpid;
1290 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1292 lpPData->dwFlags = dwFlags;
1294 /* If we were given an event handle, duplicate it */
1295 if( hEvent != 0 )
1297 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1298 GetCurrentProcess(), &lpPData->hEvent,
1299 0, FALSE, DUPLICATE_SAME_ACCESS )
1302 /* FIXME: Memory leak */
1303 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1307 /* Initialize the SP data section */
1308 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1310 TRACE( "Created player id 0x%08x\n", *lpid );
1312 if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1313 This->dp2->lpSessionDesc->dwCurrentPlayers++;
1315 return lpPData;
1318 /* Delete the contents of the DPNAME struct */
1319 static void
1320 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1322 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1323 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1326 /* This method assumes that all links to it are already deleted */
1327 static void
1328 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1330 lpPlayerList lpPList;
1332 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1334 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1336 if( lpPList == NULL )
1338 ERR( "DPID 0x%08x not found\n", dpid );
1339 return;
1342 /* Verify that this is the last reference to the data */
1343 if( --(lpPList->lpPData->uRef) )
1345 FIXME( "Why is this not the last reference to player?\n" );
1346 DebugBreak();
1349 /* Delete player */
1350 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1352 CloseHandle( lpPList->lpPData->hEvent );
1353 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1355 /* Delete Player List object */
1356 HeapFree( GetProcessHeap(), 0, lpPList );
1359 lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1361 lpPlayerList lpPlayers;
1363 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1365 if(This->dp2->lpSysGroup == NULL)
1366 return NULL;
1368 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1370 return lpPlayers;
1373 /* Basic area for Dst must already be allocated */
1374 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1376 if( lpSrc == NULL )
1378 ZeroMemory( lpDst, sizeof( *lpDst ) );
1379 lpDst->dwSize = sizeof( *lpDst );
1380 return TRUE;
1383 if( lpSrc->dwSize != sizeof( *lpSrc) )
1385 return FALSE;
1388 /* Delete any existing pointers */
1389 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1390 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1392 /* Copy as required */
1393 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1395 if( bAnsi )
1397 if( lpSrc->u1.lpszShortNameA )
1399 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1400 strlen(lpSrc->u1.lpszShortNameA)+1 );
1401 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1403 else
1405 lpDst->u1.lpszShortNameA = NULL;
1407 if( lpSrc->u2.lpszLongNameA )
1409 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1410 strlen(lpSrc->u2.lpszLongNameA)+1 );
1411 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1413 else
1415 lpDst->u2.lpszLongNameA = NULL;
1418 else
1420 if( lpSrc->u1.lpszShortNameA )
1422 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1423 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1424 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1426 else
1428 lpDst->u1.lpszShortNameA = NULL;
1430 if( lpSrc->u2.lpszLongNameA )
1432 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1433 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1434 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1436 else
1438 lpDst->u2.lpszLongNameA = NULL;
1442 return TRUE;
1445 static void
1446 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1447 LPVOID lpData, DWORD dwDataSize )
1449 /* Clear out the data with this player */
1450 if( dwFlags & DPSET_LOCAL )
1452 if ( lpPData->dwLocalDataSize != 0 )
1454 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1455 lpPData->lpLocalData = NULL;
1456 lpPData->dwLocalDataSize = 0;
1459 else
1461 if( lpPData->dwRemoteDataSize != 0 )
1463 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1464 lpPData->lpRemoteData = NULL;
1465 lpPData->dwRemoteDataSize = 0;
1469 /* Reallocate for new data */
1470 if( lpData != NULL )
1472 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1473 sizeof( dwDataSize ) );
1474 CopyMemory( lpNewData, lpData, dwDataSize );
1476 if( dwFlags & DPSET_LOCAL )
1478 lpPData->lpLocalData = lpData;
1479 lpPData->dwLocalDataSize = dwDataSize;
1481 else
1483 lpPData->lpRemoteData = lpNewData;
1484 lpPData->dwRemoteDataSize = dwDataSize;
1490 static HRESULT DP_IF_CreatePlayer
1491 ( IDirectPlay2Impl* This,
1492 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1493 LPDPID lpidPlayer,
1494 LPDPNAME lpPlayerName,
1495 HANDLE hEvent,
1496 LPVOID lpData,
1497 DWORD dwDataSize,
1498 DWORD dwFlags,
1499 BOOL bAnsi )
1501 HRESULT hr = DP_OK;
1502 lpPlayerData lpPData;
1503 lpPlayerList lpPList;
1505 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1506 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1507 dwDataSize, dwFlags, bAnsi );
1509 if( dwFlags == 0 )
1511 dwFlags = DPPLAYER_SPECTATOR;
1514 if( lpidPlayer == NULL )
1516 return DPERR_INVALIDPARAMS;
1520 /* Determine the creation flags for the player. These will be passed
1521 * to the name server if requesting a player id and to the SP when
1522 * informing it of the player creation
1525 if( dwFlags & DPPLAYER_SERVERPLAYER )
1527 if( *lpidPlayer == DPID_SERVERPLAYER )
1529 /* Server player for the host interface */
1530 dwFlags |= DPLAYI_PLAYER_APPSERVER;
1532 else if( *lpidPlayer == DPID_NAME_SERVER )
1534 /* Name server - master of everything */
1535 dwFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1537 else
1539 /* Server player for a non host interface */
1540 dwFlags |= DPLAYI_PLAYER_SYSPLAYER;
1544 if( lpMsgHdr == NULL )
1545 dwFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1548 /* Verify we know how to handle all the flags */
1549 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1550 ( dwFlags & DPPLAYER_SPECTATOR )
1554 /* Assume non fatal failure */
1555 ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1558 /* If the name is not specified, we must provide one */
1559 if( *lpidPlayer == DPID_UNKNOWN )
1561 /* If we are the session master, we dish out the group/player ids */
1562 if( This->dp2->bHostInterface )
1564 *lpidPlayer = DP_NextObjectId();
1566 else
1568 hr = DP_MSG_SendRequestPlayerId( This, dwFlags & 0x000000FF, lpidPlayer );
1570 if( FAILED(hr) )
1572 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1573 return hr;
1577 else
1579 /* Verify that we don't already have this player */
1581 lpPlayerList lpPlayers = NULL;
1582 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players,
1583 lpPData->dpid, ==, *lpidPlayer, lpPlayers );
1585 if (lpPlayers != NULL)
1587 return DPERR_CANTCREATEPLAYER;
1592 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags,
1593 hEvent, bAnsi );
1595 if( lpPData == NULL )
1597 return DPERR_CANTADDPLAYER;
1600 /* Create the list object and link it in */
1601 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1602 if( lpPList == NULL )
1604 FIXME( "Memory leak\n" );
1605 return DPERR_CANTADDPLAYER;
1608 lpPData->uRef = 1;
1609 lpPList->lpPData = lpPData;
1611 /* Add the player to the system group */
1612 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1614 /* Update the information and send it to all players in the session */
1615 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1617 /* Let the SP know that we've created this player */
1618 if( This->dp2->spData.lpCB->CreatePlayer )
1620 DPSP_CREATEPLAYERDATA data;
1622 data.idPlayer = *lpidPlayer;
1623 data.dwFlags = dwFlags;
1624 data.lpSPMessageHeader = lpMsgHdr;
1625 data.lpISP = This->dp2->spData.lpISP;
1627 TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1628 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1630 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1633 if( FAILED(hr) )
1635 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1636 return hr;
1639 /* Now let the SP know that this player is a member of the system group */
1640 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1642 DPSP_ADDPLAYERTOGROUPDATA data;
1644 data.idPlayer = *lpidPlayer;
1645 data.idGroup = DPID_SYSTEM_GROUP;
1646 data.lpISP = This->dp2->spData.lpISP;
1648 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1650 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1653 if( FAILED(hr) )
1655 ERR( "Failed to add player to sys group with sp: %s\n",
1656 DPLAYX_HresultToString(hr) );
1657 return hr;
1660 #if 1
1661 if( This->dp2->bHostInterface == FALSE )
1663 /* Let the name server know about the creation of this player */
1664 /* FIXME: Is this only to be done for the creation of a server player or
1665 * is this used for regular players? If only for server players, move
1666 * this call to DP_SecureOpen(...);
1669 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1671 #else
1672 /* Inform all other peers of the creation of a new player. If there are
1673 * no peers keep this quiet.
1674 * Also, if this was a remote event, no need to rebroadcast it.
1676 if( ( lpMsgHdr == NULL ) &&
1677 This->dp2->lpSessionDesc &&
1678 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1680 DPMSG_CREATEPLAYERORGROUP msg;
1681 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1683 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1684 msg.dpId = *lpidPlayer;
1685 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1686 msg.lpData = lpData;
1687 msg.dwDataSize = dwDataSize;
1688 msg.dpnName = *lpPlayerName;
1689 msg.dpIdParent = DPID_NOPARENT_GROUP;
1690 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1692 /* FIXME: Correct to just use send effectively? */
1693 /* FIXME: Should size include data w/ message or just message "header" */
1694 /* FIXME: Check return code */
1695 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1696 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1698 #endif
1700 return hr;
1703 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1704 ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1705 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1707 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1709 if( This->dp2->connectionInitialized == NO_PROVIDER )
1711 return DPERR_UNINITIALIZED;
1714 if( lpidPlayer == NULL || !This->dp2->bConnectionOpen )
1716 return DPERR_INVALIDPARAMS;
1719 if ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_NEWPLAYERSDISABLED )
1721 return DPERR_CANTCREATEPLAYER;
1724 if( dwFlags & DPPLAYER_SERVERPLAYER )
1726 *lpidPlayer = DPID_SERVERPLAYER;
1728 else
1730 *lpidPlayer = DPID_UNKNOWN;
1733 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1734 lpData, dwDataSize, dwFlags, TRUE );
1737 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1738 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1739 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1741 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1743 if( This->dp2->connectionInitialized == NO_PROVIDER )
1745 return DPERR_UNINITIALIZED;
1748 if( lpidPlayer == NULL || !This->dp2->bConnectionOpen )
1750 return DPERR_INVALIDPARAMS;
1753 if ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_NEWPLAYERSDISABLED )
1755 return DPERR_CANTCREATEPLAYER;
1758 if( dwFlags & DPPLAYER_SERVERPLAYER )
1760 *lpidPlayer = DPID_SERVERPLAYER;
1762 else
1764 *lpidPlayer = DPID_UNKNOWN;
1767 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1768 lpData, dwDataSize, dwFlags, FALSE );
1771 static DPID DP_GetRemoteNextObjectId(void)
1773 FIXME( ":stub\n" );
1775 /* Hack solution */
1776 return DP_NextObjectId();
1779 static HRESULT DP_IF_DeletePlayerFromGroup
1780 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1781 DPID idPlayer, BOOL bAnsi )
1783 HRESULT hr = DP_OK;
1785 lpGroupData lpGData;
1786 lpPlayerList lpPList;
1788 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
1789 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1791 /* Find the group */
1792 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1794 return DPERR_INVALIDGROUP;
1797 /* Find the player */
1798 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1800 return DPERR_INVALIDPLAYER;
1803 /* Remove the player shortcut from the group */
1804 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1806 if( lpPList == NULL )
1808 return DPERR_INVALIDPLAYER;
1811 /* One less reference */
1812 lpPList->lpPData->uRef--;
1814 /* Delete the Player List element */
1815 HeapFree( GetProcessHeap(), 0, lpPList );
1817 /* Inform the SP if they care */
1818 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1820 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1822 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1824 data.idPlayer = idPlayer;
1825 data.idGroup = idGroup;
1826 data.lpISP = This->dp2->spData.lpISP;
1828 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1831 /* Need to send a DELETEPLAYERFROMGROUP message */
1832 FIXME( "Need to send a message\n" );
1834 return hr;
1837 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1838 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1840 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1841 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1844 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1845 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1847 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1848 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1851 typedef struct _DPRGOPContext
1853 IDirectPlay3Impl* This;
1854 BOOL bAnsi;
1855 DPID idGroup;
1856 } DPRGOPContext, *lpDPRGOPContext;
1858 static BOOL CALLBACK
1859 cbRemoveGroupOrPlayer(
1860 DPID dpId,
1861 DWORD dwPlayerType,
1862 LPCDPNAME lpName,
1863 DWORD dwFlags,
1864 LPVOID lpContext )
1866 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1868 TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1869 dpId, dwPlayerType, lpCtxt->idGroup );
1871 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1873 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1874 dpId )
1878 ERR( "Unable to delete group 0x%08x from group 0x%08x\n",
1879 dpId, lpCtxt->idGroup );
1882 else
1884 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1885 NULL, lpCtxt->idGroup,
1886 dpId, lpCtxt->bAnsi )
1890 ERR( "Unable to delete player 0x%08x from grp 0x%08x\n",
1891 dpId, lpCtxt->idGroup );
1895 return TRUE; /* Continue enumeration */
1898 static HRESULT DP_IF_DestroyGroup
1899 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1901 lpGroupData lpGData;
1902 DPRGOPContext context;
1904 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1905 This, lpMsgHdr, idGroup, bAnsi );
1907 /* Find the group */
1908 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1910 return DPERR_INVALIDPLAYER; /* yes player */
1913 context.This = (IDirectPlay3Impl*)This;
1914 context.bAnsi = bAnsi;
1915 context.idGroup = idGroup;
1917 /* Remove all players that this group has */
1918 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1919 cbRemoveGroupOrPlayer, &context, 0, bAnsi );
1921 /* Remove all links to groups that this group has since this is dp3 */
1922 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1923 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1925 /* Remove this group from the parent group - if it has one */
1926 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1927 ( lpGData->parent != DPID_SYSTEM_GROUP )
1930 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1931 idGroup );
1934 /* Now delete this group data and list from the system group */
1935 DP_DeleteGroup( This, idGroup );
1937 /* Let the SP know that we've destroyed this group */
1938 if( This->dp2->spData.lpCB->DeleteGroup )
1940 DPSP_DELETEGROUPDATA data;
1942 FIXME( "data.dwFlags is incorrect\n" );
1944 data.idGroup = idGroup;
1945 data.dwFlags = 0;
1946 data.lpISP = This->dp2->spData.lpISP;
1948 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1951 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1953 return DP_OK;
1956 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1957 ( LPDIRECTPLAY2A iface, DPID idGroup )
1959 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1960 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1963 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1964 ( LPDIRECTPLAY2 iface, DPID idGroup )
1966 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1967 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1970 typedef struct _DPFAGContext
1972 IDirectPlay2Impl* This;
1973 DPID idPlayer;
1974 BOOL bAnsi;
1975 } DPFAGContext, *lpDPFAGContext;
1977 static HRESULT DP_IF_DestroyPlayer
1978 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1980 DPFAGContext cbContext;
1982 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1983 This, lpMsgHdr, idPlayer, bAnsi );
1985 if( This->dp2->connectionInitialized == NO_PROVIDER )
1987 return DPERR_UNINITIALIZED;
1990 if( DP_FindPlayer( This, idPlayer ) == NULL )
1992 return DPERR_INVALIDPLAYER;
1995 /* FIXME: If the player is remote, we must be the host to delete this */
1997 cbContext.This = This;
1998 cbContext.idPlayer = idPlayer;
1999 cbContext.bAnsi = bAnsi;
2001 /* Find each group and call DeletePlayerFromGroup if the player is a
2002 member of the group */
2003 DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
2004 &cbContext, DPENUMGROUPS_ALL, bAnsi );
2006 /* Now delete player and player list from the sys group */
2007 DP_DeletePlayer( This, idPlayer );
2009 /* Let the SP know that we've destroyed this group */
2010 if( This->dp2->spData.lpCB->DeletePlayer )
2012 DPSP_DELETEPLAYERDATA data;
2014 FIXME( "data.dwFlags is incorrect\n" );
2016 data.idPlayer = idPlayer;
2017 data.dwFlags = 0;
2018 data.lpISP = This->dp2->spData.lpISP;
2020 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
2023 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
2025 return DP_OK;
2028 static BOOL CALLBACK
2029 cbDeletePlayerFromAllGroups(
2030 DPID dpId,
2031 DWORD dwPlayerType,
2032 LPCDPNAME lpName,
2033 DWORD dwFlags,
2034 LPVOID lpContext )
2036 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
2038 if( dwPlayerType == DPPLAYERTYPE_GROUP )
2040 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
2041 lpCtxt->bAnsi );
2043 /* Enumerate all groups in this group since this will normally only
2044 * be called for top level groups
2046 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
2047 dpId, NULL,
2048 cbDeletePlayerFromAllGroups,
2049 lpContext, DPENUMGROUPS_ALL,
2050 lpCtxt->bAnsi );
2053 else
2055 ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
2058 return TRUE;
2061 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
2062 ( LPDIRECTPLAY2A iface, DPID idPlayer )
2064 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2065 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
2068 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
2069 ( LPDIRECTPLAY2 iface, DPID idPlayer )
2071 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2072 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
2075 static HRESULT DP_IF_EnumGroupPlayers
2076 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
2077 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2078 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2080 lpGroupData lpGData;
2081 lpPlayerList lpPList;
2083 FIXME("(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
2084 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
2085 lpContext, dwFlags, bAnsi );
2087 if( This->dp2->connectionInitialized == NO_PROVIDER )
2089 return DPERR_UNINITIALIZED;
2092 if( !This->dp2->bConnectionOpen )
2094 return DPERR_NOSESSIONS;
2097 if( ( lpEnumPlayersCallback2 == NULL ) ||
2098 ( ( dwFlags & DPENUMPLAYERS_SESSION ) && ( lpguidInstance == NULL ) ) )
2100 return DPERR_INVALIDPARAMS;
2103 /* Find the group */
2104 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2106 return DPERR_INVALIDGROUP;
2109 if( DPQ_IS_EMPTY( lpGData->players ) )
2111 return DP_OK;
2114 lpPList = DPQ_FIRST( lpGData->players );
2116 /* Walk the players in this group */
2117 for( ;; )
2119 /* We do not enum the name server or app server as they are of no
2120 * consequence to the end user.
2122 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
2123 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
2127 /* FIXME: Need to add stuff for dwFlags checking */
2129 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
2130 &lpPList->lpPData->name,
2131 lpPList->lpPData->dwFlags,
2132 lpContext )
2135 /* User requested break */
2136 return DP_OK;
2140 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
2142 break;
2145 lpPList = DPQ_NEXT( lpPList->players );
2148 return DP_OK;
2151 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
2152 ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
2153 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2154 LPVOID lpContext, DWORD dwFlags )
2156 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2157 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2158 lpEnumPlayersCallback2, lpContext,
2159 dwFlags, TRUE );
2162 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
2163 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
2164 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2165 LPVOID lpContext, DWORD dwFlags )
2167 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2168 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2169 lpEnumPlayersCallback2, lpContext,
2170 dwFlags, FALSE );
2173 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2174 static HRESULT DP_IF_EnumGroups
2175 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2176 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2177 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2179 return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2180 DPID_SYSTEM_GROUP, lpguidInstance,
2181 lpEnumPlayersCallback2, lpContext,
2182 dwFlags, bAnsi );
2185 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2186 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2187 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2188 LPVOID lpContext, DWORD dwFlags )
2190 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2191 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2192 lpContext, dwFlags, TRUE );
2195 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2196 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2197 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2198 LPVOID lpContext, DWORD dwFlags )
2200 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2201 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2202 lpContext, dwFlags, FALSE );
2205 static HRESULT DP_IF_EnumPlayers
2206 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2207 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2208 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2210 return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
2211 lpEnumPlayersCallback2, lpContext,
2212 dwFlags, bAnsi );
2215 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2216 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2217 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2218 LPVOID lpContext, DWORD dwFlags )
2220 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2221 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2222 lpContext, dwFlags, TRUE );
2225 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2226 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2227 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2228 LPVOID lpContext, DWORD dwFlags )
2230 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2231 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2232 lpContext, dwFlags, FALSE );
2235 /* This function should call the registered callback function that the user
2236 passed into EnumSessions for each entry available.
2238 static void DP_InvokeEnumSessionCallbacks
2239 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2240 LPVOID lpNSInfo,
2241 DWORD dwTimeout,
2242 LPVOID lpContext )
2244 LPDPSESSIONDESC2 lpSessionDesc;
2246 FIXME( ": not checking for conditions\n" );
2248 /* Not sure if this should be pruning but it's convenient */
2249 NS_PruneSessionCache( lpNSInfo );
2251 NS_ResetSessionEnumeration( lpNSInfo );
2253 /* Enumerate all sessions */
2254 /* FIXME: Need to indicate ANSI */
2255 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2257 TRACE( "EnumSessionsCallback2 invoked\n" );
2258 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2260 return;
2264 /* Invoke one last time to indicate that there is no more to come */
2265 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2268 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2270 EnumSessionAsyncCallbackData* data = lpContext;
2271 HANDLE hSuicideRequest = data->hSuicideRequest;
2272 DWORD dwTimeout = data->dwTimeout;
2274 TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
2276 for( ;; )
2278 HRESULT hr;
2280 /* Sleep up to dwTimeout waiting for request to terminate thread */
2281 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2283 TRACE( "Thread terminating on terminate request\n" );
2284 break;
2287 /* Now resend the enum request */
2288 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2289 data->dwEnumSessionFlags,
2290 data->lpSpData );
2292 if( FAILED(hr) )
2294 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2295 /* FIXME: Should we kill this thread? How to inform the main thread? */
2300 TRACE( "Thread terminating\n" );
2302 /* Clean up the thread data */
2303 CloseHandle( hSuicideRequest );
2304 HeapFree( GetProcessHeap(), 0, lpContext );
2306 /* FIXME: Need to have some notification to main app thread that this is
2307 * dead. It would serve two purposes. 1) allow sync on termination
2308 * so that we don't actually send something to ourselves when we
2309 * become name server (race condition) and 2) so that if we die
2310 * abnormally something else will be able to tell.
2313 return 1;
2316 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
2318 /* Does a thread exist? If so we were doing an async enum session */
2319 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2321 TRACE( "Killing EnumSession thread %p\n",
2322 This->dp2->hEnumSessionThread );
2324 /* Request that the thread kill itself nicely */
2325 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2326 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2328 /* We no longer need to know about the thread */
2329 CloseHandle( This->dp2->hEnumSessionThread );
2331 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2335 static HRESULT DP_IF_EnumSessions
2336 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2337 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2338 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2340 HRESULT hr = DP_OK;
2342 TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x,%u)\n",
2343 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2344 bAnsi );
2345 if( This->dp2->connectionInitialized == NO_PROVIDER )
2347 return DPERR_UNINITIALIZED;
2350 if( (lpsd == NULL) || (lpsd->dwSize != sizeof(DPSESSIONDESC2)) )
2352 return DPERR_INVALIDPARAMS;
2355 /* Can't enumerate if the session is already open */
2356 if( This->dp2->bConnectionOpen )
2358 return DPERR_GENERIC;
2361 #if 1
2362 /* The loading of a lobby provider _seems_ to require a backdoor loading
2363 * of the service provider to also associate with this DP object. This is
2364 * because the app doesn't seem to have to call EnumConnections and
2365 * InitializeConnection for the SP before calling this method. As such
2366 * we'll do their dirty work for them with a quick hack so as to always
2367 * load the TCP/IP service provider.
2369 * The correct solution would seem to involve creating a dialog box which
2370 * contains the possible SPs. These dialog boxes most likely follow SDK
2371 * examples.
2373 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2375 LPVOID lpConnection;
2376 DWORD dwSize;
2378 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2380 if( !DP_BuildCompoundAddr( DPAID_ServiceProvider, (LPGUID)&DPSPGUID_TCPIP,
2381 &lpConnection, &dwSize ) )
2383 ERR( "Can't build compound addr\n" );
2384 return DPERR_GENERIC;
2387 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2388 0, bAnsi );
2389 if( FAILED(hr) )
2391 return hr;
2394 /* Free up the address buffer */
2395 HeapFree( GetProcessHeap(), 0, lpConnection );
2397 /* The SP is now initialized */
2398 This->dp2->bSPInitialized = TRUE;
2400 #endif
2403 /* Use the service provider default? */
2404 if( dwTimeout == 0 )
2406 DPCAPS spCaps;
2407 spCaps.dwSize = sizeof( spCaps );
2409 DP_IF_GetCaps( This, &spCaps, 0 );
2410 dwTimeout = spCaps.dwTimeout;
2412 /* The service provider doesn't provide one either! */
2413 if( dwTimeout == 0 )
2415 /* Provide the TCP/IP default */
2416 dwTimeout = DPMSG_WAIT_5_SECS;
2420 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2422 DP_KillEnumSessionThread( This );
2423 return hr;
2426 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2428 /* Enumerate everything presently in the local session cache */
2429 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2430 This->dp2->lpNameServerData, dwTimeout,
2431 lpContext );
2433 if( This->dp2->dwEnumSessionLock != 0 )
2434 return DPERR_CONNECTING;
2436 /* See if we've already created a thread to service this interface */
2437 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2439 DWORD dwThreadId;
2440 This->dp2->dwEnumSessionLock++;
2442 /* Send the first enum request inline since the user may cancel a dialog
2443 * if one is presented. Also, may also have a connecting return code.
2445 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2446 dwFlags, &This->dp2->spData );
2448 if( SUCCEEDED(hr) )
2450 EnumSessionAsyncCallbackData* lpData
2451 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2452 /* FIXME: need to kill the thread on object deletion */
2453 lpData->lpSpData = &This->dp2->spData;
2455 lpData->requestGuid = lpsd->guidApplication;
2456 lpData->dwEnumSessionFlags = dwFlags;
2457 lpData->dwTimeout = dwTimeout;
2459 This->dp2->hKillEnumSessionThreadEvent =
2460 CreateEventW( NULL, TRUE, FALSE, NULL );
2462 if( !DuplicateHandle( GetCurrentProcess(),
2463 This->dp2->hKillEnumSessionThreadEvent,
2464 GetCurrentProcess(),
2465 &lpData->hSuicideRequest,
2466 0, FALSE, DUPLICATE_SAME_ACCESS )
2469 ERR( "Can't duplicate thread killing handle\n" );
2472 TRACE( ": creating EnumSessionsRequest thread\n" );
2474 This->dp2->hEnumSessionThread = CreateThread( NULL,
2476 DP_EnumSessionsSendAsyncRequestThread,
2477 lpData,
2479 &dwThreadId );
2481 This->dp2->dwEnumSessionLock--;
2484 else
2486 /* Invalidate the session cache for the interface */
2487 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2489 /* Send the broadcast for session enumeration */
2490 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2491 dwFlags,
2492 &This->dp2->spData );
2495 SleepEx( dwTimeout, FALSE );
2497 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2498 This->dp2->lpNameServerData, dwTimeout,
2499 lpContext );
2502 return hr;
2505 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2506 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2507 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2508 LPVOID lpContext, DWORD dwFlags )
2510 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2511 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2512 lpContext, dwFlags, TRUE );
2515 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2516 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2517 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2518 LPVOID lpContext, DWORD dwFlags )
2520 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2521 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2522 lpContext, dwFlags, FALSE );
2525 static HRESULT DP_IF_GetPlayerCaps
2526 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2527 DWORD dwFlags )
2529 DPSP_GETCAPSDATA data;
2531 TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
2533 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2535 return DPERR_UNINITIALIZED;
2538 if ( lpDPCaps->dwSize != sizeof(DPCAPS) )
2540 return DPERR_INVALIDPARAMS;
2543 /* Query the service provider */
2544 data.idPlayer = idPlayer;
2545 data.dwFlags = dwFlags;
2546 data.lpCaps = lpDPCaps;
2547 data.lpISP = This->dp2->spData.lpISP;
2549 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2552 static HRESULT DP_IF_GetCaps
2553 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2555 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2558 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2559 ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2561 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2562 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2565 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2566 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2568 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2569 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2572 static HRESULT DP_IF_GetGroupData
2573 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2574 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2576 lpGroupData lpGData;
2577 DWORD dwRequiredBufferSize;
2578 LPVOID lpCopyDataFrom;
2580 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2581 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2583 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2585 return DPERR_INVALIDGROUP;
2588 /* How much buffer is required? */
2589 if( dwFlags & DPSET_LOCAL )
2591 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2592 lpCopyDataFrom = lpGData->lpLocalData;
2594 else
2596 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2597 lpCopyDataFrom = lpGData->lpRemoteData;
2600 /* Is the user requesting to know how big a buffer is required? */
2601 if( ( lpData == NULL ) ||
2602 ( *lpdwDataSize < dwRequiredBufferSize )
2605 *lpdwDataSize = dwRequiredBufferSize;
2606 return DPERR_BUFFERTOOSMALL;
2609 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2611 return DP_OK;
2614 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2615 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2616 LPDWORD lpdwDataSize, DWORD dwFlags )
2618 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2619 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2620 dwFlags, TRUE );
2623 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2624 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2625 LPDWORD lpdwDataSize, DWORD dwFlags )
2627 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2628 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2629 dwFlags, FALSE );
2632 static HRESULT DP_IF_GetGroupName
2633 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2634 LPDWORD lpdwDataSize, BOOL bAnsi )
2636 lpGroupData lpGData;
2637 LPDPNAME lpName = lpData;
2638 DWORD dwRequiredDataSize;
2640 FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2641 This, idGroup, lpData, lpdwDataSize, bAnsi );
2643 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2645 return DPERR_INVALIDGROUP;
2648 dwRequiredDataSize = lpGData->name.dwSize;
2650 if( lpGData->name.u1.lpszShortNameA )
2652 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2655 if( lpGData->name.u2.lpszLongNameA )
2657 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2660 if( ( lpData == NULL ) ||
2661 ( *lpdwDataSize < dwRequiredDataSize )
2664 *lpdwDataSize = dwRequiredDataSize;
2665 return DPERR_BUFFERTOOSMALL;
2668 /* Copy the structure */
2669 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2671 if( lpGData->name.u1.lpszShortNameA )
2673 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2674 lpGData->name.u1.lpszShortNameA );
2676 else
2678 lpName->u1.lpszShortNameA = NULL;
2681 if( lpGData->name.u1.lpszShortNameA )
2683 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2684 lpGData->name.u2.lpszLongNameA );
2686 else
2688 lpName->u2.lpszLongNameA = NULL;
2691 return DP_OK;
2694 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2695 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2696 LPDWORD lpdwDataSize )
2698 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2699 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2702 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2703 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2704 LPDWORD lpdwDataSize )
2706 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2707 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2710 static HRESULT DP_IF_GetMessageCount
2711 ( IDirectPlay2Impl* This, DPID idPlayer,
2712 LPDWORD lpdwCount, BOOL bAnsi )
2714 FIXME("(%p)->(0x%08x,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2715 return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2716 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2717 bAnsi );
2720 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2721 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2723 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2724 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2727 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2728 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2730 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2731 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2734 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2735 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2737 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2738 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2739 return DP_OK;
2742 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2743 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2745 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2746 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2747 return DP_OK;
2750 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2751 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2752 DWORD dwFlags )
2754 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2755 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2758 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2759 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2760 DWORD dwFlags )
2762 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2763 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2766 static HRESULT DP_IF_GetPlayerData
2767 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2768 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2770 lpPlayerList lpPList;
2771 DWORD dwRequiredBufferSize;
2772 LPVOID lpCopyDataFrom;
2774 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2775 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2777 if( This->dp2->connectionInitialized == NO_PROVIDER )
2779 return DPERR_UNINITIALIZED;
2782 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2784 return DPERR_INVALIDPLAYER;
2787 if( lpdwDataSize == NULL )
2789 return DPERR_INVALIDPARAMS;
2792 /* How much buffer is required? */
2793 if( dwFlags & DPSET_LOCAL )
2795 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2796 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2798 else
2800 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2801 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2804 /* Is the user requesting to know how big a buffer is required? */
2805 if( ( lpData == NULL ) ||
2806 ( *lpdwDataSize < dwRequiredBufferSize )
2809 *lpdwDataSize = dwRequiredBufferSize;
2810 return DPERR_BUFFERTOOSMALL;
2813 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2815 return DP_OK;
2818 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2819 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2820 LPDWORD lpdwDataSize, DWORD dwFlags )
2822 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2823 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2824 dwFlags, TRUE );
2827 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2828 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2829 LPDWORD lpdwDataSize, DWORD dwFlags )
2831 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2832 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2833 dwFlags, FALSE );
2836 static HRESULT DP_IF_GetPlayerName
2837 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2838 LPDWORD lpdwDataSize, BOOL bAnsi )
2840 lpPlayerList lpPList;
2841 LPDPNAME lpName = lpData;
2842 DWORD dwRequiredDataSize;
2844 FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2845 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2847 if( This->dp2->connectionInitialized == NO_PROVIDER )
2849 return DPERR_UNINITIALIZED;
2852 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2854 return DPERR_INVALIDPLAYER;
2857 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2859 if( lpPList->lpPData->name.u1.lpszShortNameA )
2861 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2864 if( lpPList->lpPData->name.u2.lpszLongNameA )
2866 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2869 if( ( lpData == NULL ) ||
2870 ( *lpdwDataSize < dwRequiredDataSize )
2873 *lpdwDataSize = dwRequiredDataSize;
2874 return DPERR_BUFFERTOOSMALL;
2877 /* Copy the structure */
2878 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2880 if( lpPList->lpPData->name.u1.lpszShortNameA )
2882 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2883 lpPList->lpPData->name.u1.lpszShortNameA );
2885 else
2887 lpName->u1.lpszShortNameA = NULL;
2890 if( lpPList->lpPData->name.u2.lpszLongNameA )
2892 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2893 lpPList->lpPData->name.u2.lpszLongNameA );
2895 else
2897 lpName->u2.lpszLongNameA = NULL;
2900 return DP_OK;
2903 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2904 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2905 LPDWORD lpdwDataSize )
2907 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2908 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2911 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2912 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2913 LPDWORD lpdwDataSize )
2915 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2916 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2919 static HRESULT DP_GetSessionDesc
2920 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2921 BOOL bAnsi )
2923 DWORD dwRequiredSize;
2925 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2927 if( This->dp2->connectionInitialized == NO_PROVIDER )
2929 return DPERR_UNINITIALIZED;
2932 if( !This->dp2->bConnectionOpen )
2934 return DPERR_NOSESSIONS;
2937 if( ( lpdwDataSize == NULL ) || ( *lpdwDataSize >= MAXDWORD ) )
2939 return DPERR_INVALIDPARAMS;
2942 /* FIXME: Get from This->dp2->lpSessionDesc */
2943 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2945 if ( ( lpData == NULL ) ||
2946 ( *lpdwDataSize < dwRequiredSize )
2949 *lpdwDataSize = dwRequiredSize;
2950 return DPERR_BUFFERTOOSMALL;
2953 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2955 return DP_OK;
2958 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2959 ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2961 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2962 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2965 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2966 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2968 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2969 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2972 /* Intended only for COM compatibility. Always returns an error. */
2973 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2974 ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2976 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2977 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2978 return DPERR_ALREADYINITIALIZED;
2981 /* Intended only for COM compatibility. Always returns an error. */
2982 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2983 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2985 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2986 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2987 return DPERR_ALREADYINITIALIZED;
2991 static HRESULT DP_SecureOpen
2992 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2993 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2994 BOOL bAnsi )
2996 HRESULT hr = DP_OK;
2998 FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2999 This, lpsd, dwFlags, lpSecurity, lpCredentials );
3001 if( ( lpsd == NULL ) ||
3002 ( lpsd->dwSize != sizeof(DPSESSIONDESC2) ) )
3004 return DPERR_INVALIDPARAMS;
3007 if( This->dp2->bConnectionOpen )
3009 TRACE( ": rejecting already open connection.\n" );
3010 return DPERR_ALREADYINITIALIZED;
3013 /* If we're enumerating, kill the thread */
3014 DP_KillEnumSessionThread( This );
3016 if( dwFlags & DPOPEN_JOIN )
3018 LPDPSESSIONDESC2 current = NULL;
3019 NS_ResetSessionEnumeration( This->dp2->lpNameServerData );
3020 while( ( current = NS_WalkSessions( This->dp2->lpNameServerData ) ) )
3022 if ( IsEqualGUID( &lpsd->guidInstance, &current->guidInstance ) )
3023 break;
3025 if ( current == NULL )
3026 return DPERR_NOSESSIONS;
3028 else if( dwFlags & DPOPEN_CREATE )
3030 /* Rightoo - this computer is the host and the local computer needs to be
3031 the name server so that others can join this session */
3032 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
3034 This->dp2->bHostInterface = TRUE;
3036 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
3037 if( FAILED( hr ) )
3039 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
3040 return hr;
3044 /* Invoke the conditional callback for the service provider */
3045 if( This->dp2->spData.lpCB->Open )
3047 DPSP_OPENDATA data;
3049 FIXME( "Not all data fields are correct. Need new parameter\n" );
3051 data.bCreate = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
3052 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
3053 : NS_GetNSAddr( This->dp2->lpNameServerData );
3054 data.lpISP = This->dp2->spData.lpISP;
3055 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
3056 data.dwOpenFlags = dwFlags;
3057 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
3059 hr = (*This->dp2->spData.lpCB->Open)(&data);
3060 if( FAILED( hr ) )
3062 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
3063 return hr;
3068 /* Create the system group of which everything is a part of */
3069 DPID systemGroup = DPID_SYSTEM_GROUP;
3071 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
3072 NULL, 0, 0, TRUE );
3076 if( dwFlags & DPOPEN_JOIN )
3078 DPID dpidServerId = DPID_UNKNOWN;
3080 /* Create the server player for this interface. This way we can receive
3081 * messages for this session.
3083 /* FIXME: I suppose that we should be setting an event for a receive
3084 * type of thing. That way the messaging thread could know to wake
3085 * up. DPlay would then trigger the hEvent for the player the
3086 * message is directed to.
3088 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
3090 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
3093 else if( dwFlags & DPOPEN_CREATE )
3095 DPID dpidNameServerId = DPID_NAME_SERVER;
3097 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
3098 0, DPPLAYER_SERVERPLAYER, bAnsi );
3101 if( FAILED(hr) )
3103 ERR( "Couldn't create name server/system player: %s\n",
3104 DPLAYX_HresultToString(hr) );
3106 else
3108 This->dp2->bConnectionOpen = TRUE;
3111 return hr;
3114 static HRESULT WINAPI DirectPlay2AImpl_Open
3115 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
3117 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3118 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
3119 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
3122 static HRESULT WINAPI DirectPlay2WImpl_Open
3123 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
3125 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3126 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
3127 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
3130 static HRESULT DP_IF_Receive
3131 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
3132 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
3134 LPDPMSG lpMsg = NULL;
3136 FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
3137 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
3139 if( This->dp2->connectionInitialized == NO_PROVIDER )
3141 return DPERR_UNINITIALIZED;
3144 if( dwFlags == 0 )
3146 dwFlags = DPRECEIVE_ALL;
3149 /* If the lpData is NULL, we must be peeking the message */
3150 if( ( lpData == NULL ) &&
3151 !( dwFlags & DPRECEIVE_PEEK )
3154 return DPERR_INVALIDPARAMS;
3157 if( dwFlags & DPRECEIVE_ALL )
3159 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
3161 if( !( dwFlags & DPRECEIVE_PEEK ) )
3163 FIXME( "Remove from queue\n" );
3166 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
3167 ( dwFlags & DPRECEIVE_FROMPLAYER )
3170 FIXME( "Find matching message 0x%08x\n", dwFlags );
3172 else
3174 ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
3177 if( lpMsg == NULL )
3179 return DPERR_NOMESSAGES;
3182 /* Copy into the provided buffer */
3183 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
3185 return DP_OK;
3188 static HRESULT WINAPI DirectPlay2AImpl_Receive
3189 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
3190 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3192 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3193 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3194 lpData, lpdwDataSize, TRUE );
3197 static HRESULT WINAPI DirectPlay2WImpl_Receive
3198 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
3199 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3201 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3202 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3203 lpData, lpdwDataSize, FALSE );
3206 static HRESULT WINAPI DirectPlay2AImpl_Send
3207 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3209 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3210 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3211 0, 0, NULL, NULL, TRUE );
3214 static HRESULT WINAPI DirectPlay2WImpl_Send
3215 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3217 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3218 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3219 0, 0, NULL, NULL, FALSE );
3222 static HRESULT DP_IF_SetGroupData
3223 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3224 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3226 lpGroupData lpGData;
3228 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3229 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3231 /* Parameter check */
3232 if( ( lpData == NULL ) &&
3233 ( dwDataSize != 0 )
3236 return DPERR_INVALIDPARAMS;
3239 /* Find the pointer to the data for this player */
3240 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3242 return DPERR_INVALIDOBJECT;
3245 if( !(dwFlags & DPSET_LOCAL) )
3247 FIXME( "Was this group created by this interface?\n" );
3248 /* FIXME: If this is a remote update need to allow it but not
3249 * send a message.
3253 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3255 /* FIXME: Only send a message if this group is local to the session otherwise
3256 * it will have been rejected above
3258 if( !(dwFlags & DPSET_LOCAL) )
3260 FIXME( "Send msg?\n" );
3263 return DP_OK;
3266 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3267 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3268 DWORD dwDataSize, DWORD dwFlags )
3270 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3271 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3274 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3275 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3276 DWORD dwDataSize, DWORD dwFlags )
3278 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3279 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3282 static HRESULT DP_IF_SetGroupName
3283 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3284 DWORD dwFlags, BOOL bAnsi )
3286 lpGroupData lpGData;
3288 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3289 lpGroupName, dwFlags, bAnsi );
3291 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3293 return DPERR_INVALIDGROUP;
3296 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3298 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3299 FIXME( "Message not sent and dwFlags ignored\n" );
3301 return DP_OK;
3304 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3305 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3306 DWORD dwFlags )
3308 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3309 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3312 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3313 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3314 DWORD dwFlags )
3316 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3317 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3320 static HRESULT DP_IF_SetPlayerData
3321 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3322 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3324 lpPlayerList lpPList;
3326 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3327 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3329 if( This->dp2->connectionInitialized == NO_PROVIDER )
3331 return DPERR_UNINITIALIZED;
3334 /* Parameter check */
3335 if( ( ( lpData == NULL ) && ( dwDataSize != 0 ) ) ||
3336 ( dwDataSize >= MAXDWORD ) )
3338 return DPERR_INVALIDPARAMS;
3341 /* Find the pointer to the data for this player */
3342 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3344 return DPERR_INVALIDPLAYER;
3347 if( !(dwFlags & DPSET_LOCAL) )
3349 FIXME( "Was this group created by this interface?\n" );
3350 /* FIXME: If this is a remote update need to allow it but not
3351 * send a message.
3355 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3357 if( !(dwFlags & DPSET_LOCAL) )
3359 FIXME( "Send msg?\n" );
3362 return DP_OK;
3365 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3366 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3367 DWORD dwDataSize, DWORD dwFlags )
3369 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3370 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3371 dwFlags, TRUE );
3374 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3375 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3376 DWORD dwDataSize, DWORD dwFlags )
3378 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3379 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3380 dwFlags, FALSE );
3383 static HRESULT DP_IF_SetPlayerName
3384 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3385 DWORD dwFlags, BOOL bAnsi )
3387 lpPlayerList lpPList;
3389 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3390 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3392 if( This->dp2->connectionInitialized == NO_PROVIDER )
3394 return DPERR_UNINITIALIZED;
3397 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3399 return DPERR_INVALIDGROUP;
3402 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3404 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3405 FIXME( "Message not sent and dwFlags ignored\n" );
3407 return DP_OK;
3410 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3411 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3412 DWORD dwFlags )
3414 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3415 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3418 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3419 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3420 DWORD dwFlags )
3422 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3423 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3426 static HRESULT DP_SetSessionDesc
3427 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3428 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3430 DWORD dwRequiredSize;
3431 LPDPSESSIONDESC2 lpTempSessDesc;
3433 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3434 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3436 if( dwFlags || (lpSessDesc == NULL) )
3438 return DPERR_INVALIDPARAMS;
3441 /* Illegal combinations of flags */
3442 if ( ( lpSessDesc->dwFlags & DPSESSION_MIGRATEHOST ) &&
3443 ( lpSessDesc->dwFlags & ( DPSESSION_CLIENTSERVER |
3444 DPSESSION_MULTICASTSERVER |
3445 DPSESSION_SECURESERVER ) ) )
3447 return DPERR_INVALIDFLAGS;
3450 /* Only the host is allowed to update the session desc */
3451 if( !This->dp2->bHostInterface )
3453 return DPERR_ACCESSDENIED;
3456 /* FIXME: Copy into This->dp2->lpSessionDesc */
3457 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3458 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3460 if( lpTempSessDesc == NULL )
3462 return DPERR_OUTOFMEMORY;
3465 /* Free the old */
3466 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3468 This->dp2->lpSessionDesc = lpTempSessDesc;
3469 /* Set the new */
3470 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3471 if( bInitial )
3473 /*Initializing session GUID*/
3474 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3476 /* If this is an external invocation of the interface, we should be
3477 * letting everyone know that things have changed. Otherwise this is
3478 * just an initialization and it doesn't need to be propagated.
3480 if( !bInitial )
3482 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3485 return DP_OK;
3488 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3489 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3491 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3493 if( This->dp2->connectionInitialized == NO_PROVIDER )
3495 return DPERR_UNINITIALIZED;
3498 if( !This->dp2->bConnectionOpen )
3500 return DPERR_NOSESSIONS;
3503 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3506 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3507 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3509 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3511 if( This->dp2->connectionInitialized == NO_PROVIDER )
3513 return DPERR_UNINITIALIZED;
3516 if( !This->dp2->bConnectionOpen )
3518 return DPERR_NOSESSIONS;
3521 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3524 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3525 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3527 DWORD dwSize = 0;
3529 if( lpSessDesc == NULL )
3531 /* Hmmm..don't need any size? */
3532 ERR( "NULL lpSessDesc\n" );
3533 return dwSize;
3536 dwSize += sizeof( *lpSessDesc );
3538 if( bAnsi )
3540 if( lpSessDesc->u1.lpszSessionNameA )
3542 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3545 if( lpSessDesc->u2.lpszPasswordA )
3547 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3550 else /* UNICODE */
3552 if( lpSessDesc->u1.lpszSessionName )
3554 dwSize += sizeof( WCHAR ) *
3555 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3558 if( lpSessDesc->u2.lpszPassword )
3560 dwSize += sizeof( WCHAR ) *
3561 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3565 return dwSize;
3568 /* Assumes that contiguous buffers are already allocated. */
3569 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3570 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3572 BYTE* lpStartOfFreeSpace;
3574 if( lpSessionDest == NULL )
3576 ERR( "NULL lpSessionDest\n" );
3577 return;
3580 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3582 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3584 if( bAnsi )
3586 if( lpSessionSrc->u1.lpszSessionNameA )
3588 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3589 lpSessionDest->u1.lpszSessionNameA );
3590 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3591 lpStartOfFreeSpace +=
3592 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3595 if( lpSessionSrc->u2.lpszPasswordA )
3597 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3598 lpSessionDest->u2.lpszPasswordA );
3599 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3600 lpStartOfFreeSpace +=
3601 lstrlenA( lpSessionDest->u2.lpszPasswordA ) + 1;
3604 else /* UNICODE */
3606 if( lpSessionSrc->u1.lpszSessionName )
3608 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3609 lpSessionDest->u1.lpszSessionName );
3610 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3611 lpStartOfFreeSpace += sizeof(WCHAR) *
3612 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3615 if( lpSessionSrc->u2.lpszPassword )
3617 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3618 lpSessionDest->u2.lpszPassword );
3619 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3620 lpStartOfFreeSpace += sizeof(WCHAR) *
3621 ( lstrlenW( lpSessionDest->u2.lpszPassword ) + 1 );
3627 static HRESULT DP_IF_AddGroupToGroup
3628 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3630 lpGroupData lpGData;
3631 lpGroupList lpNewGList;
3633 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3635 if( This->dp2->connectionInitialized == NO_PROVIDER )
3637 return DPERR_UNINITIALIZED;
3640 if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3642 return DPERR_INVALIDGROUP;
3645 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3647 return DPERR_INVALIDGROUP;
3650 /* Create a player list (ie "shortcut" ) */
3651 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3652 if( lpNewGList == NULL )
3654 return DPERR_CANTADDPLAYER;
3657 /* Add the shortcut */
3658 lpGData->uRef++;
3659 lpNewGList->lpGData = lpGData;
3661 /* Add the player to the list of players for this group */
3662 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3664 /* Send a ADDGROUPTOGROUP message */
3665 FIXME( "Not sending message\n" );
3667 return DP_OK;
3670 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3671 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3673 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3674 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3677 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3678 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3680 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3681 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3684 static HRESULT DP_IF_CreateGroupInGroup
3685 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3686 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3687 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3689 lpGroupData lpGParentData;
3690 lpGroupList lpGList;
3691 lpGroupData lpGData;
3693 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3694 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3695 dwDataSize, dwFlags, bAnsi );
3697 /* Verify that the specified parent is valid */
3698 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3699 idParentGroup ) ) == NULL
3702 return DPERR_INVALIDGROUP;
3705 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3706 dwFlags, idParentGroup, bAnsi );
3708 if( lpGData == NULL )
3710 return DPERR_CANTADDPLAYER; /* yes player not group */
3713 /* Something else is referencing this data */
3714 lpGData->uRef++;
3716 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3718 /* The list has now been inserted into the interface group list. We now
3719 need to put a "shortcut" to this group in the parent group */
3720 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3721 if( lpGList == NULL )
3723 FIXME( "Memory leak\n" );
3724 return DPERR_CANTADDPLAYER; /* yes player not group */
3727 lpGList->lpGData = lpGData;
3729 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3731 /* Let the SP know that we've created this group */
3732 if( This->dp2->spData.lpCB->CreateGroup )
3734 DPSP_CREATEGROUPDATA data;
3736 TRACE( "Calling SP CreateGroup\n" );
3738 data.idGroup = *lpidGroup;
3739 data.dwFlags = dwFlags;
3740 data.lpSPMessageHeader = lpMsgHdr;
3741 data.lpISP = This->dp2->spData.lpISP;
3743 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3746 /* Inform all other peers of the creation of a new group. If there are
3747 * no peers keep this quiet.
3749 if( This->dp2->lpSessionDesc &&
3750 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3752 DPMSG_CREATEPLAYERORGROUP msg;
3754 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3755 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3756 msg.dpId = *lpidGroup;
3757 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3758 msg.lpData = lpData;
3759 msg.dwDataSize = dwDataSize;
3760 msg.dpnName = *lpGroupName;
3762 /* FIXME: Correct to just use send effectively? */
3763 /* FIXME: Should size include data w/ message or just message "header" */
3764 /* FIXME: Check return code */
3765 DP_SendEx( (IDirectPlay2Impl*)This,
3766 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3767 0, 0, NULL, NULL, bAnsi );
3770 return DP_OK;
3773 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3774 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3775 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3776 DWORD dwFlags )
3778 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3780 if( This->dp2->connectionInitialized == NO_PROVIDER )
3782 return DPERR_UNINITIALIZED;
3785 if( lpidGroup == NULL ||
3786 !This->dp2->bConnectionOpen ||
3787 dwDataSize >= MAXDWORD ||
3788 ( lpData == NULL && dwDataSize != 0 ) )
3790 return DPERR_INVALIDPARAMS;
3793 *lpidGroup = DPID_UNKNOWN;
3795 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3796 lpGroupName, lpData, dwDataSize, dwFlags,
3797 TRUE );
3800 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3801 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3802 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3803 DWORD dwFlags )
3805 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3807 if( This->dp2->connectionInitialized == NO_PROVIDER )
3809 return DPERR_UNINITIALIZED;
3812 if( lpidGroup == NULL ||
3813 !This->dp2->bConnectionOpen ||
3814 dwDataSize >= MAXDWORD ||
3815 ( lpData == NULL && dwDataSize != 0 ) )
3817 return DPERR_INVALIDPARAMS;
3820 *lpidGroup = DPID_UNKNOWN;
3822 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3823 lpGroupName, lpData, dwDataSize,
3824 dwFlags, FALSE );
3827 static HRESULT DP_IF_DeleteGroupFromGroup
3828 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3830 lpGroupList lpGList;
3831 lpGroupData lpGParentData;
3833 TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3835 /* Is the parent group valid? */
3836 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3838 return DPERR_INVALIDGROUP;
3841 /* Remove the group from the parent group queue */
3842 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3844 if( lpGList == NULL )
3846 return DPERR_INVALIDGROUP;
3849 /* Decrement the ref count */
3850 lpGList->lpGData->uRef--;
3852 /* Free up the list item */
3853 HeapFree( GetProcessHeap(), 0, lpGList );
3855 /* Should send a DELETEGROUPFROMGROUP message */
3856 FIXME( "message not sent\n" );
3858 return DP_OK;
3861 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3862 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3864 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3865 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3868 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3869 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3871 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3872 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3874 static BOOL DP_BuildCompoundAddr( GUID guidDataType,
3875 LPGUID lpcSpGuid,
3876 LPVOID* lplpAddrBuf,
3877 LPDWORD lpdwBufSize )
3879 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3880 HRESULT hr;
3882 dpCompoundAddress.dwDataSize = sizeof( GUID );
3883 dpCompoundAddress.guidDataType = guidDataType;
3884 dpCompoundAddress.lpData = lpcSpGuid;
3886 *lplpAddrBuf = NULL;
3887 *lpdwBufSize = 0;
3889 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3890 lpdwBufSize, TRUE );
3892 if( hr != DPERR_BUFFERTOOSMALL )
3894 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3895 return FALSE;
3898 /* Now allocate the buffer */
3899 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3900 *lpdwBufSize );
3902 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3903 lpdwBufSize, TRUE );
3904 if( FAILED(hr) )
3906 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3907 return FALSE;
3910 return TRUE;
3913 static HRESULT WINAPI DP_IF_EnumConnections
3914 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication,
3915 LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext,
3916 DWORD dwFlags, BOOL bAnsi )
3918 HKEY hkResult;
3919 WCHAR searchSubKeySP[] = {
3920 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
3921 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
3922 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
3923 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
3924 WCHAR searchSubKeyLP[] = {
3925 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
3926 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
3927 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
3928 'L', 'o', 'b', 'b', 'y', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
3929 WCHAR guidDataSubKey[] = { 'G', 'u', 'i', 'd', 0 };
3930 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
3931 DWORD dwIndex, sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
3932 FILETIME filetime;
3934 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3935 if( dwFlags == 0 )
3937 dwFlags = DPCONNECTION_DIRECTPLAY;
3940 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3941 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) ) )
3943 return DPERR_INVALIDFLAGS;
3946 if( !lpEnumCallback )
3948 return DPERR_INVALIDPARAMS;
3952 /* Need to loop over the service providers in the registry */
3953 if( RegOpenKeyExW( HKEY_LOCAL_MACHINE,
3954 ( dwFlags & DPCONNECTION_DIRECTPLAY ) ? searchSubKeySP
3955 : searchSubKeyLP,
3956 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3958 /* Hmmm. Does this mean that there are no service providers? */
3959 ERR(": no service providers?\n");
3960 return DP_OK;
3964 /* Traverse all the service providers we have available */
3965 for( dwIndex=0;
3966 RegEnumKeyExW( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3967 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3968 ++dwIndex, sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR) )
3970 HKEY hkServiceProvider;
3971 GUID serviceProviderGUID;
3972 WCHAR guidKeyContent[39];
3973 DWORD sizeOfReturnBuffer = sizeof(guidKeyContent);
3974 DPNAME dpName;
3975 BOOL continueEnumeration = TRUE;
3977 LPVOID lpAddressBuffer = NULL;
3978 DWORD dwAddressBufferSize = 0;
3981 TRACE(" this time through: %s\n", debugstr_w(subKeyName) );
3983 /* Get a handle for this particular service provider */
3984 if( RegOpenKeyExW( hkResult, subKeyName, 0, KEY_READ,
3985 &hkServiceProvider ) != ERROR_SUCCESS )
3987 ERR(": what the heck is going on?\n" );
3988 continue;
3991 if( RegQueryValueExW( hkServiceProvider, guidDataSubKey,
3992 NULL, NULL, (LPBYTE)guidKeyContent,
3993 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3995 ERR(": missing GUID registry data members\n" );
3996 RegCloseKey(hkServiceProvider);
3997 continue;
3999 RegCloseKey(hkServiceProvider);
4001 CLSIDFromString( guidKeyContent, &serviceProviderGUID );
4003 /* Fill in the DPNAME struct for the service provider */
4004 dpName.dwSize = sizeof( dpName );
4005 dpName.dwFlags = 0;
4006 if ( bAnsi )
4008 dpName.u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4009 sizeOfSubKeyName+1 );
4010 WideCharToMultiByte( CP_ACP, 0, subKeyName,
4011 -1, dpName.u1.lpszShortNameA, -1, 0, 0);
4012 dpName.u2.lpszLongNameA = NULL;
4014 else
4016 dpName.u1.lpszShortName = subKeyName;
4017 dpName.u2.lpszLongName = NULL;
4020 /* Create the compound address for the service provider.
4021 * NOTE: This is a gruesome architectural scar right now. DP
4022 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
4023 * native dll just gets around this little bit by allocating an
4024 * 80 byte buffer which isn't even filled with a valid compound
4025 * address. Oh well. Creating a proper compound address is the
4026 * way to go anyways despite this method taking slightly more
4027 * heap space and realtime :) */
4029 if ( DP_BuildCompoundAddr( ( ( dwFlags & DPCONNECTION_DIRECTPLAY )
4030 ? DPAID_ServiceProvider
4031 : DPAID_LobbyProvider ),
4032 &serviceProviderGUID,
4033 &lpAddressBuffer,
4034 &dwAddressBufferSize ) )
4036 /* The enumeration will return FALSE if we are not to continue */
4037 continueEnumeration = lpEnumCallback( &serviceProviderGUID, lpAddressBuffer,
4038 dwAddressBufferSize, &dpName,
4039 dwFlags, lpContext );
4041 else
4043 ERR( "Couldn't build compound address\n" );
4046 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4047 if ( bAnsi )
4048 HeapFree( GetProcessHeap(), 0, dpName.u1.lpszShortNameA );
4050 if (!continueEnumeration)
4051 return DP_OK;
4054 return DP_OK;
4057 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
4058 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
4060 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4061 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
4062 return DP_IF_EnumConnections( iface, lpguidApplication, lpEnumCallback, lpContext, dwFlags, TRUE );
4065 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
4066 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
4068 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4069 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
4070 return DP_IF_EnumConnections( iface, lpguidApplication, lpEnumCallback, lpContext, dwFlags, FALSE );
4073 static HRESULT DP_IF_EnumGroupsInGroup
4074 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
4075 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
4076 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
4078 lpGroupList lpGList;
4079 lpGroupData lpGData;
4081 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
4082 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
4083 lpContext, dwFlags, bAnsi );
4085 if( This->dp2->connectionInitialized == NO_PROVIDER )
4087 return DPERR_UNINITIALIZED;
4090 if( !This->dp2->bConnectionOpen )
4092 return DPERR_NOSESSIONS;
4095 if( ( lpEnumPlayersCallback2 == NULL ) ||
4096 ( ( dwFlags & DPENUMGROUPS_SESSION ) && ( lpguidInstance == NULL ) ) )
4098 return DPERR_INVALIDPARAMS;
4101 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4103 return DPERR_INVALIDGROUP;
4106 if( DPQ_IS_EMPTY( lpGData->groups ) )
4108 return DP_OK;
4111 lpGList = DPQ_FIRST( lpGData->groups );
4113 for( ;; )
4115 /* FIXME: Should check dwFlags for match here */
4117 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
4118 &lpGList->lpGData->name, dwFlags,
4119 lpContext ) )
4121 return DP_OK; /* User requested break */
4124 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
4126 break;
4129 lpGList = DPQ_NEXT( lpGList->groups );
4133 return DP_OK;
4136 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
4137 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
4138 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
4139 DWORD dwFlags )
4141 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4142 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
4143 lpEnumPlayersCallback2, lpContext, dwFlags,
4144 TRUE );
4147 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
4148 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
4149 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
4150 DWORD dwFlags )
4152 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4153 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
4154 lpEnumPlayersCallback2, lpContext, dwFlags,
4155 FALSE );
4158 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
4159 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4161 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4162 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4163 return DP_OK;
4166 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
4167 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4169 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4170 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4171 return DP_OK;
4174 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
4175 REFGUID guidDataType,
4176 DWORD dwDataSize,
4177 LPCVOID lpData,
4178 LPVOID lpContext )
4180 /* Looking for the GUID of the provider to load */
4181 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
4182 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
4185 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4186 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
4188 if( dwDataSize != sizeof( GUID ) )
4190 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4193 memcpy( lpContext, lpData, dwDataSize );
4195 /* There shouldn't be more than 1 GUID/compound address */
4196 return FALSE;
4199 /* Still waiting for what we want */
4200 return TRUE;
4204 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4205 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4207 UINT i;
4208 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4209 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4210 LPCSTR guidDataSubKey = "Guid";
4211 LPCSTR majVerDataSubKey = "dwReserved1";
4212 LPCSTR minVerDataSubKey = "dwReserved2";
4213 LPCSTR pathSubKey = "Path";
4215 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4217 /* FIXME: Cloned code with a quick hack. */
4218 for( i=0; i<2; i++ )
4220 HKEY hkResult;
4221 LPCSTR searchSubKey;
4222 char subKeyName[51];
4223 DWORD dwIndex, sizeOfSubKeyName=50;
4224 FILETIME filetime;
4226 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4227 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4230 /* Need to loop over the service providers in the registry */
4231 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4232 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4234 /* Hmmm. Does this mean that there are no service providers? */
4235 ERR(": no service providers?\n");
4236 return 0;
4239 /* Traverse all the service providers we have available */
4240 for( dwIndex=0;
4241 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4242 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4243 ++dwIndex, sizeOfSubKeyName=51 )
4246 HKEY hkServiceProvider;
4247 GUID serviceProviderGUID;
4248 DWORD returnType, sizeOfReturnBuffer = 255;
4249 char returnBuffer[256];
4250 WCHAR buff[51];
4251 DWORD dwTemp, len;
4253 TRACE(" this time through: %s\n", subKeyName );
4255 /* Get a handle for this particular service provider */
4256 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4257 &hkServiceProvider ) != ERROR_SUCCESS )
4259 ERR(": what the heck is going on?\n" );
4260 continue;
4263 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4264 NULL, &returnType, (LPBYTE)returnBuffer,
4265 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4267 ERR(": missing GUID registry data members\n" );
4268 continue;
4271 /* FIXME: Check return types to ensure we're interpreting data right */
4272 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4273 CLSIDFromString( buff, &serviceProviderGUID );
4274 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4276 /* Determine if this is the Service Provider that the user asked for */
4277 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4279 continue;
4282 if( i == 0 ) /* DP SP */
4284 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4285 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4286 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4289 sizeOfReturnBuffer = 255;
4291 /* Get dwReserved1 */
4292 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4293 NULL, &returnType, (LPBYTE)returnBuffer,
4294 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4296 ERR(": missing dwReserved1 registry data members\n") ;
4297 continue;
4300 if( i == 0 )
4301 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4303 sizeOfReturnBuffer = 255;
4305 /* Get dwReserved2 */
4306 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4307 NULL, &returnType, (LPBYTE)returnBuffer,
4308 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4310 ERR(": missing dwReserved1 registry data members\n") ;
4311 continue;
4314 if( i == 0 )
4315 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4317 sizeOfReturnBuffer = 255;
4319 /* Get the path for this service provider */
4320 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4321 NULL, NULL, (LPBYTE)returnBuffer,
4322 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4324 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4325 continue;
4328 TRACE( "Loading %s\n", returnBuffer );
4329 return LoadLibraryA( returnBuffer );
4333 return 0;
4336 static
4337 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4339 HRESULT hr;
4340 LPDPSP_SPINIT SPInit;
4342 /* Initialize the service provider by calling SPInit */
4343 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4345 if( SPInit == NULL )
4347 ERR( "Service provider doesn't provide SPInit interface?\n" );
4348 FreeLibrary( hServiceProvider );
4349 return DPERR_UNAVAILABLE;
4352 TRACE( "Calling SPInit (DP SP entry point)\n" );
4354 hr = (*SPInit)( &This->dp2->spData );
4356 if( FAILED(hr) )
4358 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4359 FreeLibrary( hServiceProvider );
4360 return hr;
4363 /* FIXME: Need to verify the sanity of the returned callback table
4364 * using IsBadCodePtr */
4365 This->dp2->bSPInitialized = TRUE;
4367 /* This interface is now initialized as a DP object */
4368 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4370 /* Store the handle of the module so that we can unload it later */
4371 This->dp2->hServiceProvider = hServiceProvider;
4373 return hr;
4376 static
4377 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4379 HRESULT hr;
4380 LPSP_INIT DPLSPInit;
4382 /* Initialize the service provider by calling SPInit */
4383 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4385 if( DPLSPInit == NULL )
4387 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4388 FreeLibrary( hLobbyProvider );
4389 return DPERR_UNAVAILABLE;
4392 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4394 hr = (*DPLSPInit)( &This->dp2->dplspData );
4396 if( FAILED(hr) )
4398 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4399 FreeLibrary( hLobbyProvider );
4400 return hr;
4403 /* FIXME: Need to verify the sanity of the returned callback table
4404 * using IsBadCodePtr */
4406 This->dp2->bDPLSPInitialized = TRUE;
4408 /* This interface is now initialized as a lobby object */
4409 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4411 /* Store the handle of the module so that we can unload it later */
4412 This->dp2->hDPLobbyProvider = hLobbyProvider;
4414 return hr;
4417 static HRESULT DP_IF_InitializeConnection
4418 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4420 HMODULE hServiceProvider;
4421 HRESULT hr;
4422 GUID guidSP;
4423 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4424 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4426 TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4428 if ( lpConnection == NULL )
4430 return DPERR_INVALIDPARAMS;
4433 if( dwFlags != 0 )
4435 return DPERR_INVALIDFLAGS;
4438 if( This->dp2->connectionInitialized != NO_PROVIDER )
4440 return DPERR_ALREADYINITIALIZED;
4443 /* Find out what the requested SP is and how large this buffer is */
4444 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4445 dwAddrSize, &guidSP );
4447 if( FAILED(hr) )
4449 ERR( "Invalid compound address?\n" );
4450 return DPERR_UNAVAILABLE;
4453 /* Load the service provider */
4454 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4456 if( hServiceProvider == 0 )
4458 ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4459 return DPERR_UNAVAILABLE;
4462 if( bIsDpSp )
4464 /* Fill in what we can of the Service Provider required information.
4465 * The rest was be done in DP_LoadSP
4467 This->dp2->spData.lpAddress = lpConnection;
4468 This->dp2->spData.dwAddressSize = dwAddrSize;
4469 This->dp2->spData.lpGuid = &guidSP;
4471 hr = DP_InitializeDPSP( This, hServiceProvider );
4473 else
4475 This->dp2->dplspData.lpAddress = lpConnection;
4477 hr = DP_InitializeDPLSP( This, hServiceProvider );
4480 if( FAILED(hr) )
4482 return hr;
4485 return DP_OK;
4488 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4489 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4491 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4492 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4495 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4496 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4498 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4499 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4502 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4503 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4504 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4506 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4507 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4510 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4511 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4512 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4514 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4515 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4518 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4519 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4521 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4522 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4523 return DP_OK;
4526 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4527 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4529 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4530 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4531 return DP_OK;
4534 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4535 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4537 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4538 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4539 return DP_OK;
4542 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4543 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4545 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4546 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4547 return DP_OK;
4550 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4551 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4553 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4554 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4555 return DP_OK;
4558 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4559 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4561 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4562 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4563 return DP_OK;
4566 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4567 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4569 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4570 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4571 return DP_OK;
4574 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4575 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4577 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4578 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4579 return DP_OK;
4582 static HRESULT DP_IF_GetGroupParent
4583 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4584 BOOL bAnsi )
4586 lpGroupData lpGData;
4588 TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4590 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4592 return DPERR_INVALIDGROUP;
4595 *lpidGroup = lpGData->dpid;
4597 return DP_OK;
4600 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4601 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4603 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4604 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4606 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4607 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4609 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4610 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4613 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4614 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4616 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4617 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4618 return DP_OK;
4621 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4622 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4624 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4625 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4626 return DP_OK;
4629 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4630 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4632 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4633 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4634 return DP_OK;
4637 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4638 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4640 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4641 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4642 return DP_OK;
4645 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4646 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4648 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4649 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4650 return DP_OK;
4653 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4654 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4656 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4657 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4658 return DP_OK;
4661 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4662 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4664 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4665 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4666 return DP_OK;
4669 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4670 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4672 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4673 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4674 return DP_OK;
4677 static HRESULT DP_SendEx
4678 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4679 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4680 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4682 BOOL bValidDestination = FALSE;
4684 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4685 ": stub\n",
4686 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4687 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4689 if( This->dp2->connectionInitialized == NO_PROVIDER )
4691 return DPERR_UNINITIALIZED;
4694 /* FIXME: Add parameter checking */
4695 /* FIXME: First call to this needs to acquire a message id which will be
4696 * used for multiple sends
4699 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4701 /* Verify that the message is being sent from a valid local player. The
4702 * from player may be anonymous DPID_UNKNOWN
4704 if( idFrom != DPID_UNKNOWN )
4706 if( DP_FindPlayer( This, idFrom ) == NULL )
4708 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4709 return DPERR_INVALIDPLAYER;
4713 /* Verify that the message is being sent to a valid player, group or to
4714 * everyone. If it's valid, send it to those players.
4716 if( idTo == DPID_ALLPLAYERS )
4718 bValidDestination = TRUE;
4720 /* See if SP has the ability to multicast. If so, use it */
4721 if( This->dp2->spData.lpCB->SendToGroupEx )
4723 FIXME( "Use group sendex to group 0\n" );
4725 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4727 FIXME( "Use obsolete group send to group 0\n" );
4729 else /* No multicast, multiplicate */
4731 /* Send to all players we know about */
4732 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4736 if( ( !bValidDestination ) &&
4737 ( DP_FindPlayer( This, idTo ) != NULL )
4740 bValidDestination = TRUE;
4742 /* Have the service provider send this message */
4743 /* FIXME: Could optimize for local interface sends */
4744 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4745 dwTimeout, lpContext, lpdwMsgID );
4748 if( ( !bValidDestination ) &&
4749 ( DP_FindAnyGroup( This, idTo ) != NULL )
4752 bValidDestination = TRUE;
4754 /* See if SP has the ability to multicast. If so, use it */
4755 if( This->dp2->spData.lpCB->SendToGroupEx )
4757 FIXME( "Use group sendex\n" );
4759 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4761 FIXME( "Use obsolete group send to group\n" );
4763 else /* No multicast, multiplicate */
4765 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4768 #if 0
4769 if( bExpectReply )
4771 DWORD dwWaitReturn;
4773 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4775 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4776 if( dwWaitReturn != WAIT_OBJECT_0 )
4778 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4781 #endif
4784 if( !bValidDestination )
4786 return DPERR_INVALIDPLAYER;
4788 else
4790 /* FIXME: Should return what the send returned */
4791 return DP_OK;
4796 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4797 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4798 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4799 LPVOID lpContext, LPDWORD lpdwMsgID )
4801 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4802 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4803 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4806 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4807 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4808 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4809 LPVOID lpContext, LPDWORD lpdwMsgID )
4811 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4812 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4813 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4816 static HRESULT DP_SP_SendEx
4817 ( IDirectPlay2Impl* This, DWORD dwFlags,
4818 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4819 LPVOID lpContext, LPDWORD lpdwMsgID )
4821 LPDPMSG lpMElem;
4823 FIXME( ": stub\n" );
4825 /* FIXME: This queuing should only be for async messages */
4827 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4828 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4830 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4832 /* FIXME: Need to queue based on priority */
4833 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4835 return DP_OK;
4838 static HRESULT DP_IF_GetMessageQueue
4839 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4840 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4842 HRESULT hr = DP_OK;
4844 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4845 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4847 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4848 /* FIXME: What about sends which are not immediate? */
4850 if( This->dp2->spData.lpCB->GetMessageQueue )
4852 DPSP_GETMESSAGEQUEUEDATA data;
4854 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4856 /* FIXME: None of this is documented :( */
4858 data.lpISP = This->dp2->spData.lpISP;
4859 data.dwFlags = dwFlags;
4860 data.idFrom = idFrom;
4861 data.idTo = idTo;
4862 data.lpdwNumMsgs = lpdwNumMsgs;
4863 data.lpdwNumBytes = lpdwNumBytes;
4865 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4867 else
4869 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4872 return hr;
4875 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4876 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4877 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4879 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4880 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4881 lpdwNumBytes, TRUE );
4884 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4885 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4886 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4888 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4889 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4890 lpdwNumBytes, FALSE );
4893 static HRESULT DP_IF_CancelMessage
4894 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4895 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4897 HRESULT hr = DP_OK;
4899 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4900 This, dwMsgID, dwFlags, bAnsi );
4902 if( This->dp2->spData.lpCB->Cancel )
4904 DPSP_CANCELDATA data;
4906 TRACE( "Calling SP Cancel\n" );
4908 /* FIXME: Undocumented callback */
4910 data.lpISP = This->dp2->spData.lpISP;
4911 data.dwFlags = dwFlags;
4912 data.lprglpvSPMsgID = NULL;
4913 data.cSPMsgID = dwMsgID;
4914 data.dwMinPriority = dwMinPriority;
4915 data.dwMaxPriority = dwMaxPriority;
4917 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4919 else
4921 FIXME( "SP doesn't implement Cancel\n" );
4924 return hr;
4927 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4928 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4930 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4932 if( dwFlags != 0 )
4934 return DPERR_INVALIDFLAGS;
4937 if( dwMsgID == 0 )
4939 dwFlags |= DPCANCELSEND_ALL;
4942 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4945 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4946 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4948 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4950 if( dwFlags != 0 )
4952 return DPERR_INVALIDFLAGS;
4955 if( dwMsgID == 0 )
4957 dwFlags |= DPCANCELSEND_ALL;
4960 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4963 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4964 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4965 DWORD dwFlags )
4967 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4969 if( dwFlags != 0 )
4971 return DPERR_INVALIDFLAGS;
4974 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4975 dwMaxPriority, TRUE );
4978 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4979 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4980 DWORD dwFlags )
4982 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4984 if( dwFlags != 0 )
4986 return DPERR_INVALIDFLAGS;
4989 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4990 dwMaxPriority, FALSE );
4993 /* Note: Hack so we can reuse the old functions without compiler warnings */
4994 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4995 # define XCAST(fun) (typeof(directPlay2WVT.fun))
4996 #else
4997 # define XCAST(fun) (void*)
4998 #endif
5000 static const IDirectPlay2Vtbl directPlay2WVT =
5002 XCAST(QueryInterface)DP_QueryInterface,
5003 XCAST(AddRef)DP_AddRef,
5004 XCAST(Release)DP_Release,
5006 DirectPlay2WImpl_AddPlayerToGroup,
5007 DirectPlay2WImpl_Close,
5008 DirectPlay2WImpl_CreateGroup,
5009 DirectPlay2WImpl_CreatePlayer,
5010 DirectPlay2WImpl_DeletePlayerFromGroup,
5011 DirectPlay2WImpl_DestroyGroup,
5012 DirectPlay2WImpl_DestroyPlayer,
5013 DirectPlay2WImpl_EnumGroupPlayers,
5014 DirectPlay2WImpl_EnumGroups,
5015 DirectPlay2WImpl_EnumPlayers,
5016 DirectPlay2WImpl_EnumSessions,
5017 DirectPlay2WImpl_GetCaps,
5018 DirectPlay2WImpl_GetGroupData,
5019 DirectPlay2WImpl_GetGroupName,
5020 DirectPlay2WImpl_GetMessageCount,
5021 DirectPlay2WImpl_GetPlayerAddress,
5022 DirectPlay2WImpl_GetPlayerCaps,
5023 DirectPlay2WImpl_GetPlayerData,
5024 DirectPlay2WImpl_GetPlayerName,
5025 DirectPlay2WImpl_GetSessionDesc,
5026 DirectPlay2WImpl_Initialize,
5027 DirectPlay2WImpl_Open,
5028 DirectPlay2WImpl_Receive,
5029 DirectPlay2WImpl_Send,
5030 DirectPlay2WImpl_SetGroupData,
5031 DirectPlay2WImpl_SetGroupName,
5032 DirectPlay2WImpl_SetPlayerData,
5033 DirectPlay2WImpl_SetPlayerName,
5034 DirectPlay2WImpl_SetSessionDesc
5036 #undef XCAST
5038 /* Note: Hack so we can reuse the old functions without compiler warnings */
5039 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5040 # define XCAST(fun) (typeof(directPlay2AVT.fun))
5041 #else
5042 # define XCAST(fun) (void*)
5043 #endif
5045 static const IDirectPlay2Vtbl directPlay2AVT =
5047 XCAST(QueryInterface)DP_QueryInterface,
5048 XCAST(AddRef)DP_AddRef,
5049 XCAST(Release)DP_Release,
5051 DirectPlay2AImpl_AddPlayerToGroup,
5052 DirectPlay2AImpl_Close,
5053 DirectPlay2AImpl_CreateGroup,
5054 DirectPlay2AImpl_CreatePlayer,
5055 DirectPlay2AImpl_DeletePlayerFromGroup,
5056 DirectPlay2AImpl_DestroyGroup,
5057 DirectPlay2AImpl_DestroyPlayer,
5058 DirectPlay2AImpl_EnumGroupPlayers,
5059 DirectPlay2AImpl_EnumGroups,
5060 DirectPlay2AImpl_EnumPlayers,
5061 DirectPlay2AImpl_EnumSessions,
5062 DirectPlay2AImpl_GetCaps,
5063 DirectPlay2AImpl_GetGroupData,
5064 DirectPlay2AImpl_GetGroupName,
5065 DirectPlay2AImpl_GetMessageCount,
5066 DirectPlay2AImpl_GetPlayerAddress,
5067 DirectPlay2AImpl_GetPlayerCaps,
5068 DirectPlay2AImpl_GetPlayerData,
5069 DirectPlay2AImpl_GetPlayerName,
5070 DirectPlay2AImpl_GetSessionDesc,
5071 DirectPlay2AImpl_Initialize,
5072 DirectPlay2AImpl_Open,
5073 DirectPlay2AImpl_Receive,
5074 DirectPlay2AImpl_Send,
5075 DirectPlay2AImpl_SetGroupData,
5076 DirectPlay2AImpl_SetGroupName,
5077 DirectPlay2AImpl_SetPlayerData,
5078 DirectPlay2AImpl_SetPlayerName,
5079 DirectPlay2AImpl_SetSessionDesc
5081 #undef XCAST
5084 /* Note: Hack so we can reuse the old functions without compiler warnings */
5085 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5086 # define XCAST(fun) (typeof(directPlay3AVT.fun))
5087 #else
5088 # define XCAST(fun) (void*)
5089 #endif
5091 static const IDirectPlay3Vtbl directPlay3AVT =
5093 XCAST(QueryInterface)DP_QueryInterface,
5094 XCAST(AddRef)DP_AddRef,
5095 XCAST(Release)DP_Release,
5097 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5098 XCAST(Close)DirectPlay2AImpl_Close,
5099 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5100 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5101 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5102 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5103 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5104 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5105 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5106 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5107 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5108 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5109 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5110 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5111 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5112 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5113 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5114 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5115 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5116 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5117 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5118 XCAST(Open)DirectPlay2AImpl_Open,
5119 XCAST(Receive)DirectPlay2AImpl_Receive,
5120 XCAST(Send)DirectPlay2AImpl_Send,
5121 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5122 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5123 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5124 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5125 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5127 DirectPlay3AImpl_AddGroupToGroup,
5128 DirectPlay3AImpl_CreateGroupInGroup,
5129 DirectPlay3AImpl_DeleteGroupFromGroup,
5130 DirectPlay3AImpl_EnumConnections,
5131 DirectPlay3AImpl_EnumGroupsInGroup,
5132 DirectPlay3AImpl_GetGroupConnectionSettings,
5133 DirectPlay3AImpl_InitializeConnection,
5134 DirectPlay3AImpl_SecureOpen,
5135 DirectPlay3AImpl_SendChatMessage,
5136 DirectPlay3AImpl_SetGroupConnectionSettings,
5137 DirectPlay3AImpl_StartSession,
5138 DirectPlay3AImpl_GetGroupFlags,
5139 DirectPlay3AImpl_GetGroupParent,
5140 DirectPlay3AImpl_GetPlayerAccount,
5141 DirectPlay3AImpl_GetPlayerFlags
5143 #undef XCAST
5145 /* Note: Hack so we can reuse the old functions without compiler warnings */
5146 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5147 # define XCAST(fun) (typeof(directPlay3WVT.fun))
5148 #else
5149 # define XCAST(fun) (void*)
5150 #endif
5151 static const IDirectPlay3Vtbl directPlay3WVT =
5153 XCAST(QueryInterface)DP_QueryInterface,
5154 XCAST(AddRef)DP_AddRef,
5155 XCAST(Release)DP_Release,
5157 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5158 XCAST(Close)DirectPlay2WImpl_Close,
5159 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5160 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5161 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5162 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5163 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5164 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5165 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5166 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5167 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5168 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5169 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5170 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5171 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5172 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5173 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5174 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5175 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5176 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5177 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5178 XCAST(Open)DirectPlay2WImpl_Open,
5179 XCAST(Receive)DirectPlay2WImpl_Receive,
5180 XCAST(Send)DirectPlay2WImpl_Send,
5181 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5182 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5183 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5184 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5185 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5187 DirectPlay3WImpl_AddGroupToGroup,
5188 DirectPlay3WImpl_CreateGroupInGroup,
5189 DirectPlay3WImpl_DeleteGroupFromGroup,
5190 DirectPlay3WImpl_EnumConnections,
5191 DirectPlay3WImpl_EnumGroupsInGroup,
5192 DirectPlay3WImpl_GetGroupConnectionSettings,
5193 DirectPlay3WImpl_InitializeConnection,
5194 DirectPlay3WImpl_SecureOpen,
5195 DirectPlay3WImpl_SendChatMessage,
5196 DirectPlay3WImpl_SetGroupConnectionSettings,
5197 DirectPlay3WImpl_StartSession,
5198 DirectPlay3WImpl_GetGroupFlags,
5199 DirectPlay3WImpl_GetGroupParent,
5200 DirectPlay3WImpl_GetPlayerAccount,
5201 DirectPlay3WImpl_GetPlayerFlags
5203 #undef XCAST
5205 /* Note: Hack so we can reuse the old functions without compiler warnings */
5206 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5207 # define XCAST(fun) (typeof(directPlay4WVT.fun))
5208 #else
5209 # define XCAST(fun) (void*)
5210 #endif
5211 static const IDirectPlay4Vtbl directPlay4WVT =
5213 XCAST(QueryInterface)DP_QueryInterface,
5214 XCAST(AddRef)DP_AddRef,
5215 XCAST(Release)DP_Release,
5217 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5218 XCAST(Close)DirectPlay2WImpl_Close,
5219 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5220 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5221 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5222 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5223 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5224 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5225 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5226 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5227 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5228 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5229 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5230 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5231 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5232 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5233 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5234 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5235 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5236 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5237 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5238 XCAST(Open)DirectPlay2WImpl_Open,
5239 XCAST(Receive)DirectPlay2WImpl_Receive,
5240 XCAST(Send)DirectPlay2WImpl_Send,
5241 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5242 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5243 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5244 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5245 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5247 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5248 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5249 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5250 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5251 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5252 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5253 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5254 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5255 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5256 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5257 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5258 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5259 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5260 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5261 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5263 DirectPlay4WImpl_GetGroupOwner,
5264 DirectPlay4WImpl_SetGroupOwner,
5265 DirectPlay4WImpl_SendEx,
5266 DirectPlay4WImpl_GetMessageQueue,
5267 DirectPlay4WImpl_CancelMessage,
5268 DirectPlay4WImpl_CancelPriority
5270 #undef XCAST
5273 /* Note: Hack so we can reuse the old functions without compiler warnings */
5274 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5275 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5276 #else
5277 # define XCAST(fun) (void*)
5278 #endif
5279 static const IDirectPlay4Vtbl directPlay4AVT =
5281 XCAST(QueryInterface)DP_QueryInterface,
5282 XCAST(AddRef)DP_AddRef,
5283 XCAST(Release)DP_Release,
5285 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5286 XCAST(Close)DirectPlay2AImpl_Close,
5287 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5288 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5289 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5290 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5291 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5292 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5293 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5294 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5295 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5296 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5297 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5298 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5299 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5300 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5301 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5302 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5303 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5304 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5305 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5306 XCAST(Open)DirectPlay2AImpl_Open,
5307 XCAST(Receive)DirectPlay2AImpl_Receive,
5308 XCAST(Send)DirectPlay2AImpl_Send,
5309 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5310 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5311 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5312 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5313 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5315 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5316 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5317 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5318 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5319 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5320 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5321 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5322 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5323 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5324 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5325 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5326 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5327 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5328 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5329 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5331 DirectPlay4AImpl_GetGroupOwner,
5332 DirectPlay4AImpl_SetGroupOwner,
5333 DirectPlay4AImpl_SendEx,
5334 DirectPlay4AImpl_GetMessageQueue,
5335 DirectPlay4AImpl_CancelMessage,
5336 DirectPlay4AImpl_CancelPriority
5338 #undef XCAST
5340 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5341 DPID idPlayer,
5342 LPVOID* lplpData )
5344 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5346 if( lpPlayer == NULL )
5348 return DPERR_INVALIDPLAYER;
5351 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5353 return DP_OK;
5356 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5357 DPID idPlayer,
5358 LPVOID lpData )
5360 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5362 if( lpPlayer == NULL )
5364 return DPERR_INVALIDPLAYER;
5367 lpPlayer->lpPData->lpSPPlayerData = lpData;
5369 return DP_OK;
5372 /***************************************************************************
5373 * DirectPlayEnumerateAW
5375 * The pointer to the structure lpContext will be filled with the
5376 * appropriate data for each service offered by the OS. These services are
5377 * not necessarily available on this particular machine but are defined
5378 * as simple service providers under the "Service Providers" registry key.
5379 * This structure is then passed to lpEnumCallback for each of the different
5380 * services.
5382 * This API is useful only for applications written using DirectX3 or
5383 * worse. It is superseded by IDirectPlay3::EnumConnections which also
5384 * gives information on the actual connections.
5386 * defn of a service provider:
5387 * A dynamic-link library used by DirectPlay to communicate over a network.
5388 * The service provider contains all the network-specific code required
5389 * to send and receive messages. Online services and network operators can
5390 * supply service providers to use specialized hardware, protocols, communications
5391 * media, and network resources.
5394 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5395 LPDPENUMDPCALLBACKW lpEnumCallbackW,
5396 LPVOID lpContext)
5398 HKEY hkResult;
5399 static const WCHAR searchSubKey[] = {
5400 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5401 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5402 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5403 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5404 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5405 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5407 DWORD dwIndex;
5408 FILETIME filetime;
5410 char *descriptionA = NULL;
5411 DWORD max_sizeOfDescriptionA = 0;
5412 WCHAR *descriptionW = NULL;
5413 DWORD max_sizeOfDescriptionW = 0;
5415 if (!lpEnumCallbackA && !lpEnumCallbackW)
5417 return DPERR_INVALIDPARAMS;
5420 /* Need to loop over the service providers in the registry */
5421 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5422 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5424 /* Hmmm. Does this mean that there are no service providers? */
5425 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5426 return DPERR_GENERIC;
5429 /* Traverse all the service providers we have available */
5430 dwIndex = 0;
5431 while (1)
5433 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5434 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5435 HKEY hkServiceProvider;
5436 GUID serviceProviderGUID;
5437 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5438 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5439 LONG ret_value;
5441 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5442 NULL, NULL, NULL, &filetime);
5443 if (ret_value == ERROR_NO_MORE_ITEMS)
5444 break;
5445 else if (ret_value != ERROR_SUCCESS)
5447 ERR(": could not enumerate on service provider key.\n");
5448 return DPERR_EXCEPTION;
5450 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5452 /* Open the key for this service provider */
5453 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5455 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5456 continue;
5459 /* Get the GUID from the registry */
5460 if (RegQueryValueExW(hkServiceProvider, guidKey,
5461 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5463 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5464 continue;
5466 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5468 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5469 continue;
5471 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5473 /* The enumeration will return FALSE if we are not to continue.
5475 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5476 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5477 * I think that it simply means that they are in-line with DirectX 6.0
5479 if (lpEnumCallbackA)
5481 DWORD sizeOfDescription = 0;
5483 /* Note that this is the A case of this function, so use the A variant to get the description string */
5484 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5485 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5487 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5488 continue;
5490 if (sizeOfDescription > max_sizeOfDescriptionA)
5492 HeapFree(GetProcessHeap(), 0, descriptionA);
5493 max_sizeOfDescriptionA = sizeOfDescription;
5495 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5496 RegQueryValueExA(hkServiceProvider, "DescriptionA",
5497 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5499 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5500 goto end;
5502 else
5504 DWORD sizeOfDescription = 0;
5506 if (RegQueryValueExW(hkServiceProvider, descW,
5507 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5509 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5510 continue;
5512 if (sizeOfDescription > max_sizeOfDescriptionW)
5514 HeapFree(GetProcessHeap(), 0, descriptionW);
5515 max_sizeOfDescriptionW = sizeOfDescription;
5517 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5518 RegQueryValueExW(hkServiceProvider, descW,
5519 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5521 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5522 goto end;
5525 dwIndex++;
5528 end:
5529 HeapFree(GetProcessHeap(), 0, descriptionA);
5530 HeapFree(GetProcessHeap(), 0, descriptionW);
5532 return DP_OK;
5535 /***************************************************************************
5536 * DirectPlayEnumerate [DPLAYX.9]
5537 * DirectPlayEnumerateA [DPLAYX.2]
5539 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5541 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5543 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5546 /***************************************************************************
5547 * DirectPlayEnumerateW [DPLAYX.3]
5549 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5551 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5553 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5556 typedef struct tagCreateEnum
5558 LPVOID lpConn;
5559 LPCGUID lpGuid;
5560 } CreateEnumData, *lpCreateEnumData;
5562 /* Find and copy the matching connection for the SP guid */
5563 static BOOL CALLBACK cbDPCreateEnumConnections(
5564 LPCGUID lpguidSP,
5565 LPVOID lpConnection,
5566 DWORD dwConnectionSize,
5567 LPCDPNAME lpName,
5568 DWORD dwFlags,
5569 LPVOID lpContext)
5571 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5573 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5575 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5577 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5578 dwConnectionSize );
5579 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5581 /* Found the record that we were looking for */
5582 return FALSE;
5585 /* Haven't found what were looking for yet */
5586 return TRUE;
5590 /***************************************************************************
5591 * DirectPlayCreate [DPLAYX.1]
5594 HRESULT WINAPI DirectPlayCreate
5595 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5597 HRESULT hr;
5598 LPDIRECTPLAY3A lpDP3A;
5599 CreateEnumData cbData;
5601 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5603 if( pUnk != NULL )
5605 return CLASS_E_NOAGGREGATION;
5608 if( (lplpDP == NULL) || (lpGUID == NULL) )
5610 return DPERR_INVALIDPARAMS;
5614 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5615 give them an IDirectPlay2A object and hope that doesn't cause problems */
5616 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5618 return DPERR_UNAVAILABLE;
5621 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5623 /* The GUID_NULL means don't bind a service provider. Just return the
5624 interface as is */
5625 return DP_OK;
5628 /* Bind the desired service provider since lpGUID is non NULL */
5629 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5631 /* We're going to use a DP3 interface */
5632 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5633 (LPVOID*)&lpDP3A );
5634 if( FAILED(hr) )
5636 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5637 return hr;
5640 cbData.lpConn = NULL;
5641 cbData.lpGuid = lpGUID;
5643 /* We were given a service provider, find info about it... */
5644 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5645 &cbData, DPCONNECTION_DIRECTPLAY );
5646 if( ( FAILED(hr) ) ||
5647 ( cbData.lpConn == NULL )
5650 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5651 IDirectPlayX_Release( lpDP3A );
5652 return DPERR_UNAVAILABLE;
5655 /* Initialize the service provider */
5656 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5657 if( FAILED(hr) )
5659 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5660 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5661 IDirectPlayX_Release( lpDP3A );
5662 return hr;
5665 /* Release our version of the interface now that we're done with it */
5666 IDirectPlayX_Release( lpDP3A );
5667 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5669 return DP_OK;