dplayx: Made DP_SetSessionDesc public to use it from external modules
[wine/gsoc_dplay.git] / dlls / dplayx / dplay.c
blobdf37609685ee83cdd5b7c80870178dba1f024919
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_SecureOpen
148 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
149 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
150 BOOL bAnsi );
151 static HRESULT DP_SendEx
152 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
153 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
154 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
155 static HRESULT DP_IF_Receive
156 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
157 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
158 static HRESULT DP_IF_GetMessageQueue
159 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
160 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
161 static HRESULT DP_SP_SendEx
162 ( IDirectPlay2Impl* This, DWORD dwFlags,
163 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
164 LPVOID lpContext, LPDWORD lpdwMsgID );
165 static HRESULT DP_IF_SetGroupData
166 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
167 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
168 static HRESULT DP_IF_GetPlayerCaps
169 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
170 DWORD dwFlags );
171 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
172 static HRESULT DP_IF_CancelMessage
173 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
174 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
175 static HRESULT DP_IF_EnumGroupsInGroup
176 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
177 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
178 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
179 static HRESULT DP_IF_GetGroupParent
180 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
181 BOOL bAnsi );
182 static HRESULT DP_IF_GetCaps
183 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
184 static HRESULT DP_IF_EnumSessions
185 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
186 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
187 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
188 static HRESULT DP_IF_InitializeConnection
189 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
190 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
191 LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
192 DWORD dwFlags, LPVOID lpContext );
193 static BOOL DP_BuildCompoundAddr( GUID guidDataType, LPGUID lpcSpGuid,
194 LPVOID* lplpAddrBuf, LPDWORD lpdwBufSize );
198 static inline DPID DP_NextObjectId(void);
199 static DPID DP_GetRemoteNextObjectId(void);
201 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
202 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
203 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
206 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
207 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
208 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
215 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
216 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
217 we don't have to change much */
218 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
220 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
221 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
223 /* Strip out all dwFlags values for CREATEPLAYER msg */
224 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
226 static LONG kludgePlayerGroupId = 1000;
228 /* ------------------------------------------------------------------ */
231 static BOOL DP_CreateIUnknown( LPVOID lpDP )
233 IDirectPlay2AImpl *This = lpDP;
235 This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
236 if ( This->unk == NULL )
238 return FALSE;
241 InitializeCriticalSection( &This->unk->DP_lock );
242 This->unk->DP_lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlay2AImpl*->DirectPlayIUnknownData*->DP_lock");
244 return TRUE;
247 static BOOL DP_DestroyIUnknown( LPVOID lpDP )
249 IDirectPlay2AImpl *This = lpDP;
251 This->unk->DP_lock.DebugInfo->Spare[0] = 0;
252 DeleteCriticalSection( &This->unk->DP_lock );
253 HeapFree( GetProcessHeap(), 0, This->unk );
255 return TRUE;
258 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
260 IDirectPlay2AImpl *This = lpDP;
262 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
263 if ( This->dp2 == NULL )
265 return FALSE;
268 This->dp2->bConnectionOpen = FALSE;
270 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
271 This->dp2->dwEnumSessionLock = 0;
273 This->dp2->bHostInterface = FALSE;
275 DPQ_INIT(This->dp2->receiveMsgs);
276 DPQ_INIT(This->dp2->sendMsgs);
277 DPQ_INIT(This->dp2->replysExpected);
279 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
281 /* FIXME: Memory leak */
282 return FALSE;
285 /* Provide an initial session desc with nothing in it */
286 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
287 HEAP_ZERO_MEMORY,
288 sizeof( *This->dp2->lpSessionDesc ) );
289 if( This->dp2->lpSessionDesc == NULL )
291 /* FIXME: Memory leak */
292 return FALSE;
294 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
296 /* We are emulating a dp 6 implementation */
297 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
299 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
300 sizeof( *This->dp2->spData.lpCB ) );
301 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
302 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
304 /* This is the pointer to the service provider */
305 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
306 (LPVOID*)&This->dp2->spData.lpISP, This ) )
309 /* FIXME: Memory leak */
310 return FALSE;
313 /* Setup lobby provider information */
314 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
315 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
316 sizeof( *This->dp2->dplspData.lpCB ) );
317 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
319 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
320 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
323 /* FIXME: Memory leak */
324 return FALSE;
327 return TRUE;
330 /* Definition of the global function in dplayx_queue.h. #
331 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
332 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
334 HeapFree( GetProcessHeap(), 0, elem );
337 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
339 IDirectPlay2AImpl *This = lpDP;
341 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
343 TerminateThread( This->dp2->hEnumSessionThread, 0 );
344 CloseHandle( This->dp2->hEnumSessionThread );
347 /* Finish with the SP - have it shutdown */
348 if( This->dp2->spData.lpCB->ShutdownEx )
350 DPSP_SHUTDOWNDATA data;
352 TRACE( "Calling SP ShutdownEx\n" );
354 data.lpISP = This->dp2->spData.lpISP;
356 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
358 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
360 TRACE( "Calling obsolete SP Shutdown\n" );
361 (*This->dp2->spData.lpCB->Shutdown)();
364 /* Unload the SP (if it exists) */
365 if( This->dp2->hServiceProvider != 0 )
367 FreeLibrary( This->dp2->hServiceProvider );
370 /* Unload the Lobby Provider (if it exists) */
371 if( This->dp2->hDPLobbyProvider != 0 )
373 FreeLibrary( This->dp2->hDPLobbyProvider );
376 /* FIXME: Need to delete receive and send msgs queue contents */
378 NS_DeleteSessionCache( This->dp2->lpNameServerData );
380 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
382 IDirectPlaySP_Release( This->dp2->spData.lpISP );
384 /* Delete the contents */
385 HeapFree( GetProcessHeap(), 0, This->dp2 );
387 return TRUE;
390 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
392 IDirectPlay3AImpl *This = lpDP;
394 This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
395 if ( This->dp3 == NULL )
397 return FALSE;
400 return TRUE;
403 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
405 IDirectPlay3AImpl *This = lpDP;
407 /* Delete the contents */
408 HeapFree( GetProcessHeap(), 0, This->dp3 );
410 return TRUE;
413 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
415 IDirectPlay4AImpl *This = lpDP;
417 This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
418 if ( This->dp4 == NULL )
420 return FALSE;
423 return TRUE;
426 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
428 IDirectPlay3AImpl *This = lpDP;
430 /* Delete the contents */
431 HeapFree( GetProcessHeap(), 0, This->dp4 );
433 return TRUE;
437 /* Create a new interface */
438 HRESULT DP_CreateInterface
439 ( REFIID riid, LPVOID* ppvObj )
441 TRACE( " for %s\n", debugstr_guid( riid ) );
443 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
444 sizeof( IDirectPlay2Impl ) );
446 if( *ppvObj == NULL )
448 return DPERR_OUTOFMEMORY;
451 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
453 IDirectPlay2Impl *This = *ppvObj;
454 This->lpVtbl = &directPlay2WVT;
456 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
458 IDirectPlay2AImpl *This = *ppvObj;
459 This->lpVtbl = &directPlay2AVT;
461 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
463 IDirectPlay3Impl *This = *ppvObj;
464 This->lpVtbl = &directPlay3WVT;
466 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
468 IDirectPlay3AImpl *This = *ppvObj;
469 This->lpVtbl = &directPlay3AVT;
471 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
473 IDirectPlay4Impl *This = *ppvObj;
474 This->lpVtbl = &directPlay4WVT;
476 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
478 IDirectPlay4AImpl *This = *ppvObj;
479 This->lpVtbl = &directPlay4AVT;
481 else
483 /* Unsupported interface */
484 HeapFree( GetProcessHeap(), 0, *ppvObj );
485 *ppvObj = NULL;
487 return E_NOINTERFACE;
490 /* Initialize it */
491 if ( DP_CreateIUnknown( *ppvObj ) &&
492 DP_CreateDirectPlay2( *ppvObj ) &&
493 DP_CreateDirectPlay3( *ppvObj ) &&
494 DP_CreateDirectPlay4( *ppvObj )
497 IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
499 return S_OK;
502 /* Initialize failed, destroy it */
503 DP_DestroyDirectPlay4( *ppvObj );
504 DP_DestroyDirectPlay3( *ppvObj );
505 DP_DestroyDirectPlay2( *ppvObj );
506 DP_DestroyIUnknown( *ppvObj );
508 HeapFree( GetProcessHeap(), 0, *ppvObj );
510 *ppvObj = NULL;
511 return DPERR_NOMEMORY;
515 /* Direct Play methods */
517 /* Shared between all dplay types */
518 static HRESULT WINAPI DP_QueryInterface
519 ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
521 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
522 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
524 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
525 sizeof( *This ) );
527 if( *ppvObj == NULL )
529 return DPERR_OUTOFMEMORY;
532 CopyMemory( *ppvObj, This, sizeof( *This ) );
533 (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
535 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
537 IDirectPlay2Impl *This = *ppvObj;
538 This->lpVtbl = &directPlay2WVT;
540 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
542 IDirectPlay2AImpl *This = *ppvObj;
543 This->lpVtbl = &directPlay2AVT;
545 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
547 IDirectPlay3Impl *This = *ppvObj;
548 This->lpVtbl = &directPlay3WVT;
550 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
552 IDirectPlay3AImpl *This = *ppvObj;
553 This->lpVtbl = &directPlay3AVT;
555 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
557 IDirectPlay4Impl *This = *ppvObj;
558 This->lpVtbl = &directPlay4WVT;
560 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
562 IDirectPlay4AImpl *This = *ppvObj;
563 This->lpVtbl = &directPlay4AVT;
565 else
567 /* Unsupported interface */
568 HeapFree( GetProcessHeap(), 0, *ppvObj );
569 *ppvObj = NULL;
571 return E_NOINTERFACE;
574 IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
576 return S_OK;
579 /* Shared between all dplay types */
580 static ULONG WINAPI DP_AddRef
581 ( LPDIRECTPLAY3 iface )
583 ULONG ulInterfaceRefCount, ulObjRefCount;
584 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
586 ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
587 ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
589 TRACE( "ref count incremented to %u:%u for %p\n",
590 ulInterfaceRefCount, ulObjRefCount, This );
592 return ulObjRefCount;
595 static ULONG WINAPI DP_Release
596 ( LPDIRECTPLAY3 iface )
598 ULONG ulInterfaceRefCount, ulObjRefCount;
600 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
602 ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
603 ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
605 TRACE( "ref count decremented to %u:%u for %p\n",
606 ulInterfaceRefCount, ulObjRefCount, This );
608 /* Deallocate if this is the last reference to the object */
609 if( ulObjRefCount == 0 )
611 /* If we're destroying the object, this must be the last ref
612 of the last interface */
613 DP_DestroyDirectPlay4( This );
614 DP_DestroyDirectPlay3( This );
615 DP_DestroyDirectPlay2( This );
616 DP_DestroyIUnknown( This );
619 /* Deallocate the interface */
620 if( ulInterfaceRefCount == 0 )
622 HeapFree( GetProcessHeap(), 0, This );
625 return ulObjRefCount;
628 static inline DPID DP_NextObjectId(void)
630 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
633 /* *lplpReply will be non NULL iff there is something to reply */
634 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
635 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
636 WORD wCommandId, WORD wVersion,
637 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
639 TRACE( "(%p)->(%p,0x%08x,%p,0x%x,%u)\n",
640 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
641 wVersion );
643 switch( wCommandId )
645 /* Name server needs to handle this request */
646 case DPMSGCMD_ENUMSESSIONS:
648 /* Reply expected */
649 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
651 break;
654 /* Name server needs to handle this request */
655 case DPMSGCMD_ENUMSESSIONSREPLY:
657 /* No reply expected */
658 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
659 This->dp2->spData.dwSPHeaderSize,
660 lpcMessageBody,
661 This->dp2->lpNameServerData );
662 break;
665 case DPMSGCMD_REQUESTPLAYERID:
667 LPDPSP_MSG_REQUESTPLAYERID lpcMsg = lpcMessageBody;
668 LPDPSP_MSG_REQUESTPLAYERREPLY lpReply;
670 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
672 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
674 lpReply = (LPDPSP_MSG_REQUESTPLAYERREPLY)( (LPBYTE)(*lplpReply) +
675 This->dp2->spData.dwSPHeaderSize );
677 lpReply->envelope.dwMagic = DPMSG_SIGNATURE;
678 lpReply->envelope.wCommandId = DPMSGCMD_REQUESTPLAYERREPLY;
679 lpReply->envelope.wVersion = DX61AVERSION;
681 if ( lpcMsg->Flags & DPLAYI_PLAYER_SYSPLAYER )
683 /* Request to join the game */
685 if ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_SECURESERVER )
687 FIXME( "Fill lpReply->SecDesc with Game->SSPIProvider\n" );
689 FIXME( "Fill lpReply->CAPIProvider with Game->CAPIProvider\n" );
690 FIXME( "Fill lpReply->SecDesc->dwEncryptionAlgorithm with Game->EncryptionAlgorithm\n" );
692 /* Player is not local anymore */
693 lpcMsg->Flags ^= DPLAYI_PLAYER_PLAYERLOCAL;
695 lpReply->ID = DP_NextObjectId();
696 lpReply->Result = DP_IF_CreatePlayer( This, lpcMessageHeader,
697 &lpReply->ID, NULL, 0, NULL, 0,
698 lpcMsg->Flags, TRUE/*TODO*/ );
699 lpReply->Result = S_OK;
701 else
703 /* Request to to add a normal player from an
704 * existing member of the session */
706 if ( ( This->dp2->lpSessionDesc->dwCurrentPlayers
707 == This->dp2->lpSessionDesc->dwMaxPlayers ) ||
708 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_NEWPLAYERSDISABLED ) )
710 lpReply->Result = DPERR_NONEWPLAYERS;
712 else
714 lpReply->ID = DP_NextObjectId();
715 lpReply->Result = S_OK;
719 break;
722 case DPMSGCMD_PACKET:
724 LPCDPSP_MSG_PACKET lpcMsg = lpcMessageBody;
725 LPDPSP_MSG_ENVELOPE packetData;
727 /* TODO: We have to wait for all the messages in the sequence and
728 * assemble them in a bigger message. */
729 if ( lpcMsg->TotalPackets > 1 )
731 FIXME( "TODO: Message belongs to a sequence of %d, implement assembly\n",
732 lpcMsg->TotalPackets );
733 return DPERR_GENERIC;
736 /* For now, for simplicity we'll just decapsulate the embedded
737 * message and work with it. */
738 packetData = (LPVOID)(lpcMsg + 1);
740 TRACE( "Processing embedded message with envelope (0x%08x, 0x%08x, %d)\n",
741 packetData->dwMagic, packetData->wCommandId, packetData->wVersion );
743 return DP_HandleMessage( This,
744 packetData,
745 lpcMsg->DataSize,
746 lpcMessageHeader,
747 packetData->wCommandId,
748 packetData->wVersion,
749 lplpReply, lpdwMsgSize );
750 break;
753 case DPMSGCMD_REQUESTPLAYERREPLY:
755 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageHeader,
756 lpcMessageBody, dwMessageBodySize );
757 break;
760 case DPMSGCMD_ADDFORWARDREQUEST:
762 /*LPCDPSP_MSG_ADDFORWARDREQUEST lpcMsg =
763 (LPCDPSP_MSG_ADDFORWARDREQUEST) lpcMessageBody;*/
765 /* TODO: Send ADDFORWARD messages to all the players to populate
766 * their name tables.
767 * Start NametablePopulation timer and wait for ADDFORWARDACKs */
768 FIXME( "Spread name table population messages\n" );
770 /* TODO remember to set local addr somewhere */
771 /* call NS_SetLocalAddr with a SOCKADDR_IN */
773 FIXME( "This should happen after we received all the DPMSGCMD_ADDFORWARDACKs\n" );
774 DP_MSG_ReplyToEnumPlayersRequest( This, lplpReply, lpdwMsgSize );
776 break;
779 case DPMSGCMD_ADDFORWARDREPLY:
781 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageHeader,
782 lpcMessageBody, dwMessageBodySize );
783 break;
786 case DPMSGCMD_ENUMPLAYERSREPLY:
787 case DPMSGCMD_SUPERENUMPLAYERSREPLY:
789 /* If we're joining a session, when we receive this
790 * command we were waiting for a ADDFORWARDREPLY */
791 if ( !DP_MSG_ReplyReceived( This, DPMSGCMD_ADDFORWARDREPLY,
792 lpcMessageHeader, lpcMessageBody,
793 dwMessageBodySize ) )
795 /* If we were not joining a session, check if we are
796 * waiting for an enumeration of players or groups */
797 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageHeader,
798 lpcMessageBody, dwMessageBodySize );
800 break;
803 case DPMSGCMD_ADDFORWARDACK:
805 /* When we receive an ADDFORWARDACK for each of the ADDFORWARDs
806 * we've sent, send a SUPERENUMPLAYERSREPLY back to the peer
807 * that sent the ADDFORWARDREQUEST */
808 /* TODO: We'll skip this for now and just send the SUPERENUMPLAYERSREPLY
809 * right away when we get a ADDFORWARDREQUEST */
810 break;
813 default:
815 FIXME( "Unknown wCommandId 0x%08x. Ignoring message\n", wCommandId );
816 return DPERR_GENERIC;
820 return DP_OK;
824 static HRESULT DP_IF_AddPlayerToGroup
825 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
826 DPID idPlayer, BOOL bAnsi )
828 lpGroupData lpGData;
829 lpPlayerList lpPList;
830 lpPlayerList lpNewPList;
832 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
833 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
835 if( This->dp2->connectionInitialized == NO_PROVIDER )
837 return DPERR_UNINITIALIZED;
840 /* Find the group */
841 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
843 return DPERR_INVALIDGROUP;
846 /* Find the player */
847 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
849 return DPERR_INVALIDPLAYER;
852 /* Create a player list (ie "shortcut" ) */
853 lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
854 if( lpNewPList == NULL )
856 return DPERR_CANTADDPLAYER;
859 /* Add the shortcut */
860 lpPList->lpPData->uRef++;
861 lpNewPList->lpPData = lpPList->lpPData;
863 /* Add the player to the list of players for this group */
864 DPQ_INSERT(lpGData->players,lpNewPList,players);
866 /* Let the SP know that we've added a player to the group */
867 if( This->dp2->spData.lpCB->AddPlayerToGroup )
869 DPSP_ADDPLAYERTOGROUPDATA data;
871 TRACE( "Calling SP AddPlayerToGroup\n" );
873 data.idPlayer = idPlayer;
874 data.idGroup = idGroup;
875 data.lpISP = This->dp2->spData.lpISP;
877 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
880 /* Inform all other peers of the addition of player to the group. If there are
881 * no peers keep this event quiet.
882 * Also, if this event was the result of another machine sending it to us,
883 * don't bother rebroadcasting it.
885 if( ( lpMsgHdr == NULL ) &&
886 This->dp2->lpSessionDesc &&
887 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
889 DPMSG_ADDPLAYERTOGROUP msg;
890 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
892 msg.dpIdGroup = idGroup;
893 msg.dpIdPlayer = idPlayer;
895 /* FIXME: Correct to just use send effectively? */
896 /* FIXME: Should size include data w/ message or just message "header" */
897 /* FIXME: Check return code */
898 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
901 return DP_OK;
904 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
905 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
907 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
908 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
911 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
912 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
914 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
915 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
918 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
920 HRESULT hr = DP_OK;
922 TRACE("(%p)->(%u)\n", This, bAnsi );
924 /* FIXME: Need to find a new host I assume (how?) */
925 /* FIXME: Need to destroy all local groups */
926 /* FIXME: Need to migrate all remotely visible players to the new host */
928 /* Invoke the SP callback to inform of session close */
929 if( This->dp2->spData.lpCB->CloseEx )
931 DPSP_CLOSEDATA data;
933 TRACE( "Calling SP CloseEx\n" );
935 data.lpISP = This->dp2->spData.lpISP;
937 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
940 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
942 TRACE( "Calling SP Close (obsolete interface)\n" );
944 hr = (*This->dp2->spData.lpCB->Close)();
947 if ( !FAILED(hr) )
949 This->dp2->bConnectionOpen = FALSE;
952 return hr;
955 static HRESULT WINAPI DirectPlay2AImpl_Close
956 ( LPDIRECTPLAY2A iface )
958 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
959 return DP_IF_Close( This, TRUE );
962 static HRESULT WINAPI DirectPlay2WImpl_Close
963 ( LPDIRECTPLAY2 iface )
965 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
966 return DP_IF_Close( This, FALSE );
969 static
970 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
971 const DPNAME *lpName, DWORD dwFlags,
972 DPID idParent, BOOL bAnsi )
974 lpGroupData lpGData;
976 /* Allocate the new space and add to end of high level group list */
977 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
979 if( lpGData == NULL )
981 return NULL;
984 DPQ_INIT(lpGData->groups);
985 DPQ_INIT(lpGData->players);
987 /* Set the desired player ID - no sanity checking to see if it exists */
988 lpGData->dpid = *lpid;
990 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
992 /* FIXME: Should we check that the parent exists? */
993 lpGData->parent = idParent;
995 /* FIXME: Should we validate the dwFlags? */
996 lpGData->dwFlags = dwFlags;
998 TRACE( "Created group id 0x%08x\n", *lpid );
1000 return lpGData;
1003 /* This method assumes that all links to it are already deleted */
1004 static void
1005 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
1007 lpGroupList lpGList;
1009 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1011 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
1013 if( lpGList == NULL )
1015 ERR( "DPID 0x%08x not found\n", dpid );
1016 return;
1019 if( --(lpGList->lpGData->uRef) )
1021 FIXME( "Why is this not the last reference to group?\n" );
1022 DebugBreak();
1025 /* Delete player */
1026 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
1027 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
1029 /* Remove and Delete Player List object */
1030 HeapFree( GetProcessHeap(), 0, lpGList );
1034 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
1036 lpGroupList lpGroups;
1038 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1040 if( dpid == DPID_SYSTEM_GROUP )
1042 return This->dp2->lpSysGroup;
1044 else
1046 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
1049 if( lpGroups == NULL )
1051 return NULL;
1054 return lpGroups->lpGData;
1057 static HRESULT DP_IF_CreateGroup
1058 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
1059 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
1060 DWORD dwFlags, BOOL bAnsi )
1062 lpGroupData lpGData;
1064 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1065 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
1066 dwFlags, bAnsi );
1068 /* If the name is not specified, we must provide one */
1069 if( DPID_UNKNOWN == *lpidGroup )
1071 /* If we are the name server, we decide on the group ids. If not, we
1072 * must ask for one before attempting a creation.
1074 if( This->dp2->bHostInterface )
1076 *lpidGroup = DP_NextObjectId();
1078 else
1080 *lpidGroup = DP_GetRemoteNextObjectId();
1084 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1085 DPID_NOPARENT_GROUP, bAnsi );
1087 if( lpGData == NULL )
1089 return DPERR_CANTADDPLAYER; /* yes player not group */
1092 if( DPID_SYSTEM_GROUP == *lpidGroup )
1094 This->dp2->lpSysGroup = lpGData;
1095 TRACE( "Inserting system group\n" );
1097 else
1099 /* Insert into the system group */
1100 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1101 lpGroup->lpGData = lpGData;
1103 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1106 /* Something is now referencing this data */
1107 lpGData->uRef++;
1109 /* Set all the important stuff for the group */
1110 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1112 /* FIXME: We should only create the system group if GetCaps returns
1113 * DPCAPS_GROUPOPTIMIZED.
1116 /* Let the SP know that we've created this group */
1117 if( This->dp2->spData.lpCB->CreateGroup )
1119 DPSP_CREATEGROUPDATA data;
1120 DWORD dwCreateFlags = 0;
1122 TRACE( "Calling SP CreateGroup\n" );
1124 if( *lpidGroup == DPID_NOPARENT_GROUP )
1125 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1127 if( lpMsgHdr == NULL )
1128 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1130 if( dwFlags & DPGROUP_HIDDEN )
1131 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1133 data.idGroup = *lpidGroup;
1134 data.dwFlags = dwCreateFlags;
1135 data.lpSPMessageHeader = lpMsgHdr;
1136 data.lpISP = This->dp2->spData.lpISP;
1138 (*This->dp2->spData.lpCB->CreateGroup)( &data );
1141 /* Inform all other peers of the creation of a new group. If there are
1142 * no peers keep this event quiet.
1143 * Also if this message was sent to us, don't rebroadcast.
1145 if( ( lpMsgHdr == NULL ) &&
1146 This->dp2->lpSessionDesc &&
1147 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1149 DPMSG_CREATEPLAYERORGROUP msg;
1150 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1152 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
1153 msg.dpId = *lpidGroup;
1154 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1155 msg.lpData = lpData;
1156 msg.dwDataSize = dwDataSize;
1157 msg.dpnName = *lpGroupName;
1158 msg.dpIdParent = DPID_NOPARENT_GROUP;
1159 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1161 /* FIXME: Correct to just use send effectively? */
1162 /* FIXME: Should size include data w/ message or just message "header" */
1163 /* FIXME: Check return code */
1164 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
1165 0, 0, NULL, NULL, bAnsi );
1168 return DP_OK;
1171 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
1172 ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1173 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1175 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1177 if( This->dp2->connectionInitialized == NO_PROVIDER )
1179 return DPERR_UNINITIALIZED;
1182 if( lpidGroup == NULL ||
1183 !This->dp2->bConnectionOpen ||
1184 dwDataSize >= MAXDWORD ||
1185 ( lpData == NULL && dwDataSize != 0 ) )
1187 return DPERR_INVALIDPARAMS;
1190 *lpidGroup = DPID_UNKNOWN;
1192 return DP_IF_CreateGroup( This, NULL, lpidGroup,
1193 lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
1196 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1197 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1198 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1200 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1202 if( This->dp2->connectionInitialized == NO_PROVIDER )
1204 return DPERR_UNINITIALIZED;
1207 if( lpidGroup == NULL ||
1208 !This->dp2->bConnectionOpen ||
1209 dwDataSize >= MAXDWORD ||
1210 ( lpData == NULL && dwDataSize != 0 ) )
1212 return DPERR_INVALIDPARAMS;
1215 *lpidGroup = DPID_UNKNOWN;
1217 return DP_IF_CreateGroup( This, NULL, lpidGroup,
1218 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
1222 static void
1223 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1224 LPVOID lpData, DWORD dwDataSize )
1226 /* Clear out the data with this player */
1227 if( dwFlags & DPSET_LOCAL )
1229 if ( lpGData->dwLocalDataSize != 0 )
1231 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1232 lpGData->lpLocalData = NULL;
1233 lpGData->dwLocalDataSize = 0;
1236 else
1238 if( lpGData->dwRemoteDataSize != 0 )
1240 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1241 lpGData->lpRemoteData = NULL;
1242 lpGData->dwRemoteDataSize = 0;
1246 /* Reallocate for new data */
1247 if( lpData != NULL )
1249 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1250 sizeof( dwDataSize ) );
1251 CopyMemory( lpNewData, lpData, dwDataSize );
1253 if( dwFlags & DPSET_LOCAL )
1255 lpGData->lpLocalData = lpData;
1256 lpGData->dwLocalDataSize = dwDataSize;
1258 else
1260 lpGData->lpRemoteData = lpNewData;
1261 lpGData->dwRemoteDataSize = dwDataSize;
1267 /* This function will just create the storage for the new player. */
1268 static
1269 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1270 LPDPNAME lpName, DWORD dwFlags,
1271 HANDLE hEvent, BOOL bAnsi )
1273 lpPlayerData lpPData;
1275 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1277 /* Allocate the storage for the player and associate it with list element */
1278 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1279 if( lpPData == NULL )
1281 return NULL;
1284 /* Set the desired player ID */
1285 lpPData->dpid = *lpid;
1287 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1289 lpPData->dwFlags = dwFlags;
1291 /* If we were given an event handle, duplicate it */
1292 if( hEvent != 0 )
1294 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1295 GetCurrentProcess(), &lpPData->hEvent,
1296 0, FALSE, DUPLICATE_SAME_ACCESS )
1299 /* FIXME: Memory leak */
1300 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1304 /* Initialize the SP data section */
1305 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1307 TRACE( "Created player id 0x%08x\n", *lpid );
1309 if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1310 This->dp2->lpSessionDesc->dwCurrentPlayers++;
1312 return lpPData;
1315 /* Delete the contents of the DPNAME struct */
1316 static void
1317 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1319 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1320 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1323 /* This method assumes that all links to it are already deleted */
1324 static void
1325 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1327 lpPlayerList lpPList;
1329 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1331 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1333 if( lpPList == NULL )
1335 ERR( "DPID 0x%08x not found\n", dpid );
1336 return;
1339 /* Verify that this is the last reference to the data */
1340 if( --(lpPList->lpPData->uRef) )
1342 FIXME( "Why is this not the last reference to player?\n" );
1343 DebugBreak();
1346 /* Delete player */
1347 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1349 CloseHandle( lpPList->lpPData->hEvent );
1350 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1352 /* Delete Player List object */
1353 HeapFree( GetProcessHeap(), 0, lpPList );
1356 lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1358 lpPlayerList lpPlayers;
1360 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1362 if(This->dp2->lpSysGroup == NULL)
1363 return NULL;
1365 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1367 return lpPlayers;
1370 /* Basic area for Dst must already be allocated */
1371 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1373 if( lpSrc == NULL )
1375 ZeroMemory( lpDst, sizeof( *lpDst ) );
1376 lpDst->dwSize = sizeof( *lpDst );
1377 return TRUE;
1380 if( lpSrc->dwSize != sizeof( *lpSrc) )
1382 return FALSE;
1385 /* Delete any existing pointers */
1386 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1387 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1389 /* Copy as required */
1390 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1392 if( bAnsi )
1394 if( lpSrc->u1.lpszShortNameA )
1396 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1397 strlen(lpSrc->u1.lpszShortNameA)+1 );
1398 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1400 else
1402 lpDst->u1.lpszShortNameA = NULL;
1404 if( lpSrc->u2.lpszLongNameA )
1406 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1407 strlen(lpSrc->u2.lpszLongNameA)+1 );
1408 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1410 else
1412 lpDst->u2.lpszLongNameA = NULL;
1415 else
1417 if( lpSrc->u1.lpszShortNameA )
1419 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1420 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1421 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1423 else
1425 lpDst->u1.lpszShortNameA = NULL;
1427 if( lpSrc->u2.lpszLongNameA )
1429 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1430 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1431 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1433 else
1435 lpDst->u2.lpszLongNameA = NULL;
1439 return TRUE;
1442 static void
1443 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1444 LPVOID lpData, DWORD dwDataSize )
1446 /* Clear out the data with this player */
1447 if( dwFlags & DPSET_LOCAL )
1449 if ( lpPData->dwLocalDataSize != 0 )
1451 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1452 lpPData->lpLocalData = NULL;
1453 lpPData->dwLocalDataSize = 0;
1456 else
1458 if( lpPData->dwRemoteDataSize != 0 )
1460 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1461 lpPData->lpRemoteData = NULL;
1462 lpPData->dwRemoteDataSize = 0;
1466 /* Reallocate for new data */
1467 if( lpData != NULL )
1469 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1470 sizeof( dwDataSize ) );
1471 CopyMemory( lpNewData, lpData, dwDataSize );
1473 if( dwFlags & DPSET_LOCAL )
1475 lpPData->lpLocalData = lpData;
1476 lpPData->dwLocalDataSize = dwDataSize;
1478 else
1480 lpPData->lpRemoteData = lpNewData;
1481 lpPData->dwRemoteDataSize = dwDataSize;
1487 static HRESULT DP_IF_CreatePlayer
1488 ( IDirectPlay2Impl* This,
1489 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1490 LPDPID lpidPlayer,
1491 LPDPNAME lpPlayerName,
1492 HANDLE hEvent,
1493 LPVOID lpData,
1494 DWORD dwDataSize,
1495 DWORD dwFlags,
1496 BOOL bAnsi )
1498 HRESULT hr = DP_OK;
1499 lpPlayerData lpPData;
1500 lpPlayerList lpPList;
1502 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1503 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1504 dwDataSize, dwFlags, bAnsi );
1506 if( dwFlags == 0 )
1508 dwFlags = DPPLAYER_SPECTATOR;
1511 if( lpidPlayer == NULL )
1513 return DPERR_INVALIDPARAMS;
1517 /* Determine the creation flags for the player. These will be passed
1518 * to the name server if requesting a player id and to the SP when
1519 * informing it of the player creation
1522 if( dwFlags & DPPLAYER_SERVERPLAYER )
1524 if( *lpidPlayer == DPID_SERVERPLAYER )
1526 /* Server player for the host interface */
1527 dwFlags |= DPLAYI_PLAYER_APPSERVER;
1529 else if( *lpidPlayer == DPID_NAME_SERVER )
1531 /* Name server - master of everything */
1532 dwFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1534 else
1536 /* Server player for a non host interface */
1537 dwFlags |= DPLAYI_PLAYER_SYSPLAYER;
1541 if( lpMsgHdr == NULL )
1542 dwFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1545 /* Verify we know how to handle all the flags */
1546 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1547 ( dwFlags & DPPLAYER_SPECTATOR )
1551 /* Assume non fatal failure */
1552 ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1555 /* If the name is not specified, we must provide one */
1556 if( *lpidPlayer == DPID_UNKNOWN )
1558 /* If we are the session master, we dish out the group/player ids */
1559 if( This->dp2->bHostInterface )
1561 *lpidPlayer = DP_NextObjectId();
1563 else
1565 hr = DP_MSG_SendRequestPlayerId( This, dwFlags & 0x000000FF, lpidPlayer );
1567 if( FAILED(hr) )
1569 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1570 return hr;
1574 else
1576 /* Verify that we don't already have this player */
1578 lpPlayerList lpPlayers = NULL;
1579 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players,
1580 lpPData->dpid, ==, *lpidPlayer, lpPlayers );
1582 if (lpPlayers != NULL)
1584 return DPERR_CANTCREATEPLAYER;
1589 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags,
1590 hEvent, bAnsi );
1592 if( lpPData == NULL )
1594 return DPERR_CANTADDPLAYER;
1597 /* Create the list object and link it in */
1598 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1599 if( lpPList == NULL )
1601 FIXME( "Memory leak\n" );
1602 return DPERR_CANTADDPLAYER;
1605 lpPData->uRef = 1;
1606 lpPList->lpPData = lpPData;
1608 /* Add the player to the system group */
1609 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1611 /* Update the information and send it to all players in the session */
1612 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1614 /* Let the SP know that we've created this player */
1615 if( This->dp2->spData.lpCB->CreatePlayer )
1617 DPSP_CREATEPLAYERDATA data;
1619 data.idPlayer = *lpidPlayer;
1620 data.dwFlags = dwFlags;
1621 data.lpSPMessageHeader = lpMsgHdr;
1622 data.lpISP = This->dp2->spData.lpISP;
1624 TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1625 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1627 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1630 if( FAILED(hr) )
1632 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1633 return hr;
1636 /* Now let the SP know that this player is a member of the system group */
1637 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1639 DPSP_ADDPLAYERTOGROUPDATA data;
1641 data.idPlayer = *lpidPlayer;
1642 data.idGroup = DPID_SYSTEM_GROUP;
1643 data.lpISP = This->dp2->spData.lpISP;
1645 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1647 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1650 if( FAILED(hr) )
1652 ERR( "Failed to add player to sys group with sp: %s\n",
1653 DPLAYX_HresultToString(hr) );
1654 return hr;
1657 #if 1
1658 if( This->dp2->bHostInterface == FALSE )
1660 /* Let the name server know about the creation of this player */
1661 /* FIXME: Is this only to be done for the creation of a server player or
1662 * is this used for regular players? If only for server players, move
1663 * this call to DP_SecureOpen(...);
1666 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1668 #else
1669 /* Inform all other peers of the creation of a new player. If there are
1670 * no peers keep this quiet.
1671 * Also, if this was a remote event, no need to rebroadcast it.
1673 if( ( lpMsgHdr == NULL ) &&
1674 This->dp2->lpSessionDesc &&
1675 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1677 DPMSG_CREATEPLAYERORGROUP msg;
1678 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1680 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1681 msg.dpId = *lpidPlayer;
1682 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1683 msg.lpData = lpData;
1684 msg.dwDataSize = dwDataSize;
1685 msg.dpnName = *lpPlayerName;
1686 msg.dpIdParent = DPID_NOPARENT_GROUP;
1687 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1689 /* FIXME: Correct to just use send effectively? */
1690 /* FIXME: Should size include data w/ message or just message "header" */
1691 /* FIXME: Check return code */
1692 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1693 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1695 #endif
1697 return hr;
1700 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1701 ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1702 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1704 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1706 if( This->dp2->connectionInitialized == NO_PROVIDER )
1708 return DPERR_UNINITIALIZED;
1711 if( lpidPlayer == NULL || !This->dp2->bConnectionOpen )
1713 return DPERR_INVALIDPARAMS;
1716 if ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_NEWPLAYERSDISABLED )
1718 return DPERR_CANTCREATEPLAYER;
1721 if( dwFlags & DPPLAYER_SERVERPLAYER )
1723 *lpidPlayer = DPID_SERVERPLAYER;
1725 else
1727 *lpidPlayer = DPID_UNKNOWN;
1730 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1731 lpData, dwDataSize, dwFlags, TRUE );
1734 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1735 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1736 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1738 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1740 if( This->dp2->connectionInitialized == NO_PROVIDER )
1742 return DPERR_UNINITIALIZED;
1745 if( lpidPlayer == NULL || !This->dp2->bConnectionOpen )
1747 return DPERR_INVALIDPARAMS;
1750 if ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_NEWPLAYERSDISABLED )
1752 return DPERR_CANTCREATEPLAYER;
1755 if( dwFlags & DPPLAYER_SERVERPLAYER )
1757 *lpidPlayer = DPID_SERVERPLAYER;
1759 else
1761 *lpidPlayer = DPID_UNKNOWN;
1764 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1765 lpData, dwDataSize, dwFlags, FALSE );
1768 static DPID DP_GetRemoteNextObjectId(void)
1770 FIXME( ":stub\n" );
1772 /* Hack solution */
1773 return DP_NextObjectId();
1776 static HRESULT DP_IF_DeletePlayerFromGroup
1777 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1778 DPID idPlayer, BOOL bAnsi )
1780 HRESULT hr = DP_OK;
1782 lpGroupData lpGData;
1783 lpPlayerList lpPList;
1785 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
1786 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1788 /* Find the group */
1789 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1791 return DPERR_INVALIDGROUP;
1794 /* Find the player */
1795 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1797 return DPERR_INVALIDPLAYER;
1800 /* Remove the player shortcut from the group */
1801 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1803 if( lpPList == NULL )
1805 return DPERR_INVALIDPLAYER;
1808 /* One less reference */
1809 lpPList->lpPData->uRef--;
1811 /* Delete the Player List element */
1812 HeapFree( GetProcessHeap(), 0, lpPList );
1814 /* Inform the SP if they care */
1815 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1817 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1819 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1821 data.idPlayer = idPlayer;
1822 data.idGroup = idGroup;
1823 data.lpISP = This->dp2->spData.lpISP;
1825 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1828 /* Need to send a DELETEPLAYERFROMGROUP message */
1829 FIXME( "Need to send a message\n" );
1831 return hr;
1834 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1835 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1837 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1838 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1841 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1842 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1844 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1845 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1848 typedef struct _DPRGOPContext
1850 IDirectPlay3Impl* This;
1851 BOOL bAnsi;
1852 DPID idGroup;
1853 } DPRGOPContext, *lpDPRGOPContext;
1855 static BOOL CALLBACK
1856 cbRemoveGroupOrPlayer(
1857 DPID dpId,
1858 DWORD dwPlayerType,
1859 LPCDPNAME lpName,
1860 DWORD dwFlags,
1861 LPVOID lpContext )
1863 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1865 TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1866 dpId, dwPlayerType, lpCtxt->idGroup );
1868 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1870 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1871 dpId )
1875 ERR( "Unable to delete group 0x%08x from group 0x%08x\n",
1876 dpId, lpCtxt->idGroup );
1879 else
1881 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1882 NULL, lpCtxt->idGroup,
1883 dpId, lpCtxt->bAnsi )
1887 ERR( "Unable to delete player 0x%08x from grp 0x%08x\n",
1888 dpId, lpCtxt->idGroup );
1892 return TRUE; /* Continue enumeration */
1895 static HRESULT DP_IF_DestroyGroup
1896 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1898 lpGroupData lpGData;
1899 DPRGOPContext context;
1901 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1902 This, lpMsgHdr, idGroup, bAnsi );
1904 /* Find the group */
1905 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1907 return DPERR_INVALIDPLAYER; /* yes player */
1910 context.This = (IDirectPlay3Impl*)This;
1911 context.bAnsi = bAnsi;
1912 context.idGroup = idGroup;
1914 /* Remove all players that this group has */
1915 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1916 cbRemoveGroupOrPlayer, &context, 0, bAnsi );
1918 /* Remove all links to groups that this group has since this is dp3 */
1919 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1920 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1922 /* Remove this group from the parent group - if it has one */
1923 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1924 ( lpGData->parent != DPID_SYSTEM_GROUP )
1927 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1928 idGroup );
1931 /* Now delete this group data and list from the system group */
1932 DP_DeleteGroup( This, idGroup );
1934 /* Let the SP know that we've destroyed this group */
1935 if( This->dp2->spData.lpCB->DeleteGroup )
1937 DPSP_DELETEGROUPDATA data;
1939 FIXME( "data.dwFlags is incorrect\n" );
1941 data.idGroup = idGroup;
1942 data.dwFlags = 0;
1943 data.lpISP = This->dp2->spData.lpISP;
1945 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1948 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1950 return DP_OK;
1953 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1954 ( LPDIRECTPLAY2A iface, DPID idGroup )
1956 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1957 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1960 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1961 ( LPDIRECTPLAY2 iface, DPID idGroup )
1963 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1964 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1967 typedef struct _DPFAGContext
1969 IDirectPlay2Impl* This;
1970 DPID idPlayer;
1971 BOOL bAnsi;
1972 } DPFAGContext, *lpDPFAGContext;
1974 static HRESULT DP_IF_DestroyPlayer
1975 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1977 DPFAGContext cbContext;
1979 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1980 This, lpMsgHdr, idPlayer, bAnsi );
1982 if( This->dp2->connectionInitialized == NO_PROVIDER )
1984 return DPERR_UNINITIALIZED;
1987 if( DP_FindPlayer( This, idPlayer ) == NULL )
1989 return DPERR_INVALIDPLAYER;
1992 /* FIXME: If the player is remote, we must be the host to delete this */
1994 cbContext.This = This;
1995 cbContext.idPlayer = idPlayer;
1996 cbContext.bAnsi = bAnsi;
1998 /* Find each group and call DeletePlayerFromGroup if the player is a
1999 member of the group */
2000 DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
2001 &cbContext, DPENUMGROUPS_ALL, bAnsi );
2003 /* Now delete player and player list from the sys group */
2004 DP_DeletePlayer( This, idPlayer );
2006 /* Let the SP know that we've destroyed this group */
2007 if( This->dp2->spData.lpCB->DeletePlayer )
2009 DPSP_DELETEPLAYERDATA data;
2011 FIXME( "data.dwFlags is incorrect\n" );
2013 data.idPlayer = idPlayer;
2014 data.dwFlags = 0;
2015 data.lpISP = This->dp2->spData.lpISP;
2017 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
2020 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
2022 return DP_OK;
2025 static BOOL CALLBACK
2026 cbDeletePlayerFromAllGroups(
2027 DPID dpId,
2028 DWORD dwPlayerType,
2029 LPCDPNAME lpName,
2030 DWORD dwFlags,
2031 LPVOID lpContext )
2033 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
2035 if( dwPlayerType == DPPLAYERTYPE_GROUP )
2037 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
2038 lpCtxt->bAnsi );
2040 /* Enumerate all groups in this group since this will normally only
2041 * be called for top level groups
2043 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
2044 dpId, NULL,
2045 cbDeletePlayerFromAllGroups,
2046 lpContext, DPENUMGROUPS_ALL,
2047 lpCtxt->bAnsi );
2050 else
2052 ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
2055 return TRUE;
2058 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
2059 ( LPDIRECTPLAY2A iface, DPID idPlayer )
2061 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2062 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
2065 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
2066 ( LPDIRECTPLAY2 iface, DPID idPlayer )
2068 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2069 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
2072 static HRESULT DP_IF_EnumGroupPlayers
2073 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
2074 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2075 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2077 lpGroupData lpGData;
2078 lpPlayerList lpPList;
2080 FIXME("(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
2081 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
2082 lpContext, dwFlags, bAnsi );
2084 if( This->dp2->connectionInitialized == NO_PROVIDER )
2086 return DPERR_UNINITIALIZED;
2089 if( !This->dp2->bConnectionOpen )
2091 return DPERR_NOSESSIONS;
2094 if( ( lpEnumPlayersCallback2 == NULL ) ||
2095 ( ( dwFlags & DPENUMPLAYERS_SESSION ) && ( lpguidInstance == NULL ) ) )
2097 return DPERR_INVALIDPARAMS;
2100 /* Find the group */
2101 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2103 return DPERR_INVALIDGROUP;
2106 if( DPQ_IS_EMPTY( lpGData->players ) )
2108 return DP_OK;
2111 lpPList = DPQ_FIRST( lpGData->players );
2113 /* Walk the players in this group */
2114 for( ;; )
2116 /* We do not enum the name server or app server as they are of no
2117 * consequence to the end user.
2119 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
2120 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
2124 /* FIXME: Need to add stuff for dwFlags checking */
2126 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
2127 &lpPList->lpPData->name,
2128 lpPList->lpPData->dwFlags,
2129 lpContext )
2132 /* User requested break */
2133 return DP_OK;
2137 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
2139 break;
2142 lpPList = DPQ_NEXT( lpPList->players );
2145 return DP_OK;
2148 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
2149 ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
2150 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2151 LPVOID lpContext, DWORD dwFlags )
2153 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2154 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2155 lpEnumPlayersCallback2, lpContext,
2156 dwFlags, TRUE );
2159 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
2160 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
2161 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2162 LPVOID lpContext, DWORD dwFlags )
2164 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2165 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2166 lpEnumPlayersCallback2, lpContext,
2167 dwFlags, FALSE );
2170 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2171 static HRESULT DP_IF_EnumGroups
2172 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2173 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2174 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2176 return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2177 DPID_SYSTEM_GROUP, lpguidInstance,
2178 lpEnumPlayersCallback2, lpContext,
2179 dwFlags, bAnsi );
2182 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2183 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2184 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2185 LPVOID lpContext, DWORD dwFlags )
2187 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2188 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2189 lpContext, dwFlags, TRUE );
2192 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2193 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2194 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2195 LPVOID lpContext, DWORD dwFlags )
2197 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2198 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2199 lpContext, dwFlags, FALSE );
2202 static HRESULT DP_IF_EnumPlayers
2203 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2204 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2205 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2207 return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
2208 lpEnumPlayersCallback2, lpContext,
2209 dwFlags, bAnsi );
2212 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2213 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2214 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2215 LPVOID lpContext, DWORD dwFlags )
2217 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2218 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2219 lpContext, dwFlags, TRUE );
2222 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2223 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2224 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2225 LPVOID lpContext, DWORD dwFlags )
2227 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2228 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2229 lpContext, dwFlags, FALSE );
2232 /* This function should call the registered callback function that the user
2233 passed into EnumSessions for each entry available.
2235 static void DP_InvokeEnumSessionCallbacks
2236 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2237 LPVOID lpNSInfo,
2238 DWORD dwTimeout,
2239 LPVOID lpContext )
2241 LPDPSESSIONDESC2 lpSessionDesc;
2243 FIXME( ": not checking for conditions\n" );
2245 /* Not sure if this should be pruning but it's convenient */
2246 NS_PruneSessionCache( lpNSInfo );
2248 NS_ResetSessionEnumeration( lpNSInfo );
2250 /* Enumerate all sessions */
2251 /* FIXME: Need to indicate ANSI */
2252 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2254 TRACE( "EnumSessionsCallback2 invoked\n" );
2255 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2257 return;
2261 /* Invoke one last time to indicate that there is no more to come */
2262 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2265 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2267 EnumSessionAsyncCallbackData* data = lpContext;
2268 HANDLE hSuicideRequest = data->hSuicideRequest;
2269 DWORD dwTimeout = data->dwTimeout;
2271 TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
2273 for( ;; )
2275 HRESULT hr;
2277 /* Sleep up to dwTimeout waiting for request to terminate thread */
2278 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2280 TRACE( "Thread terminating on terminate request\n" );
2281 break;
2284 /* Now resend the enum request */
2285 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2286 data->dwEnumSessionFlags,
2287 data->lpSpData );
2289 if( FAILED(hr) )
2291 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2292 /* FIXME: Should we kill this thread? How to inform the main thread? */
2297 TRACE( "Thread terminating\n" );
2299 /* Clean up the thread data */
2300 CloseHandle( hSuicideRequest );
2301 HeapFree( GetProcessHeap(), 0, lpContext );
2303 /* FIXME: Need to have some notification to main app thread that this is
2304 * dead. It would serve two purposes. 1) allow sync on termination
2305 * so that we don't actually send something to ourselves when we
2306 * become name server (race condition) and 2) so that if we die
2307 * abnormally something else will be able to tell.
2310 return 1;
2313 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
2315 /* Does a thread exist? If so we were doing an async enum session */
2316 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2318 TRACE( "Killing EnumSession thread %p\n",
2319 This->dp2->hEnumSessionThread );
2321 /* Request that the thread kill itself nicely */
2322 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2323 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2325 /* We no longer need to know about the thread */
2326 CloseHandle( This->dp2->hEnumSessionThread );
2328 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2332 static HRESULT DP_IF_EnumSessions
2333 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2334 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2335 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2337 HRESULT hr = DP_OK;
2339 TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x,%u)\n",
2340 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2341 bAnsi );
2342 if( This->dp2->connectionInitialized == NO_PROVIDER )
2344 return DPERR_UNINITIALIZED;
2347 if( (lpsd == NULL) || (lpsd->dwSize != sizeof(DPSESSIONDESC2)) )
2349 return DPERR_INVALIDPARAMS;
2352 /* Can't enumerate if the session is already open */
2353 if( This->dp2->bConnectionOpen )
2355 return DPERR_GENERIC;
2358 #if 1
2359 /* The loading of a lobby provider _seems_ to require a backdoor loading
2360 * of the service provider to also associate with this DP object. This is
2361 * because the app doesn't seem to have to call EnumConnections and
2362 * InitializeConnection for the SP before calling this method. As such
2363 * we'll do their dirty work for them with a quick hack so as to always
2364 * load the TCP/IP service provider.
2366 * The correct solution would seem to involve creating a dialog box which
2367 * contains the possible SPs. These dialog boxes most likely follow SDK
2368 * examples.
2370 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2372 LPVOID lpConnection;
2373 DWORD dwSize;
2375 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2377 if( !DP_BuildCompoundAddr( DPAID_ServiceProvider, (LPGUID)&DPSPGUID_TCPIP,
2378 &lpConnection, &dwSize ) )
2380 ERR( "Can't build compound addr\n" );
2381 return DPERR_GENERIC;
2384 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2385 0, bAnsi );
2386 if( FAILED(hr) )
2388 return hr;
2391 /* Free up the address buffer */
2392 HeapFree( GetProcessHeap(), 0, lpConnection );
2394 /* The SP is now initialized */
2395 This->dp2->bSPInitialized = TRUE;
2397 #endif
2400 /* Use the service provider default? */
2401 if( dwTimeout == 0 )
2403 DPCAPS spCaps;
2404 spCaps.dwSize = sizeof( spCaps );
2406 DP_IF_GetCaps( This, &spCaps, 0 );
2407 dwTimeout = spCaps.dwTimeout;
2409 /* The service provider doesn't provide one either! */
2410 if( dwTimeout == 0 )
2412 /* Provide the TCP/IP default */
2413 dwTimeout = DPMSG_WAIT_5_SECS;
2417 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2419 DP_KillEnumSessionThread( This );
2420 return hr;
2423 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2425 /* Enumerate everything presently in the local session cache */
2426 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2427 This->dp2->lpNameServerData, dwTimeout,
2428 lpContext );
2430 if( This->dp2->dwEnumSessionLock != 0 )
2431 return DPERR_CONNECTING;
2433 /* See if we've already created a thread to service this interface */
2434 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2436 DWORD dwThreadId;
2437 This->dp2->dwEnumSessionLock++;
2439 /* Send the first enum request inline since the user may cancel a dialog
2440 * if one is presented. Also, may also have a connecting return code.
2442 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2443 dwFlags, &This->dp2->spData );
2445 if( SUCCEEDED(hr) )
2447 EnumSessionAsyncCallbackData* lpData
2448 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2449 /* FIXME: need to kill the thread on object deletion */
2450 lpData->lpSpData = &This->dp2->spData;
2452 lpData->requestGuid = lpsd->guidApplication;
2453 lpData->dwEnumSessionFlags = dwFlags;
2454 lpData->dwTimeout = dwTimeout;
2456 This->dp2->hKillEnumSessionThreadEvent =
2457 CreateEventW( NULL, TRUE, FALSE, NULL );
2459 if( !DuplicateHandle( GetCurrentProcess(),
2460 This->dp2->hKillEnumSessionThreadEvent,
2461 GetCurrentProcess(),
2462 &lpData->hSuicideRequest,
2463 0, FALSE, DUPLICATE_SAME_ACCESS )
2466 ERR( "Can't duplicate thread killing handle\n" );
2469 TRACE( ": creating EnumSessionsRequest thread\n" );
2471 This->dp2->hEnumSessionThread = CreateThread( NULL,
2473 DP_EnumSessionsSendAsyncRequestThread,
2474 lpData,
2476 &dwThreadId );
2478 This->dp2->dwEnumSessionLock--;
2481 else
2483 /* Invalidate the session cache for the interface */
2484 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2486 /* Send the broadcast for session enumeration */
2487 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2488 dwFlags,
2489 &This->dp2->spData );
2492 SleepEx( dwTimeout, FALSE );
2494 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2495 This->dp2->lpNameServerData, dwTimeout,
2496 lpContext );
2499 return hr;
2502 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2503 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2504 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2505 LPVOID lpContext, DWORD dwFlags )
2507 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2508 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2509 lpContext, dwFlags, TRUE );
2512 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2513 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2514 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2515 LPVOID lpContext, DWORD dwFlags )
2517 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2518 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2519 lpContext, dwFlags, FALSE );
2522 static HRESULT DP_IF_GetPlayerCaps
2523 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2524 DWORD dwFlags )
2526 DPSP_GETCAPSDATA data;
2528 TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
2530 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2532 return DPERR_UNINITIALIZED;
2535 if ( lpDPCaps->dwSize != sizeof(DPCAPS) )
2537 return DPERR_INVALIDPARAMS;
2540 /* Query the service provider */
2541 data.idPlayer = idPlayer;
2542 data.dwFlags = dwFlags;
2543 data.lpCaps = lpDPCaps;
2544 data.lpISP = This->dp2->spData.lpISP;
2546 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2549 static HRESULT DP_IF_GetCaps
2550 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2552 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2555 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2556 ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2558 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2559 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2562 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2563 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2565 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2566 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2569 static HRESULT DP_IF_GetGroupData
2570 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2571 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2573 lpGroupData lpGData;
2574 DWORD dwRequiredBufferSize;
2575 LPVOID lpCopyDataFrom;
2577 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2578 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2580 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2582 return DPERR_INVALIDGROUP;
2585 /* How much buffer is required? */
2586 if( dwFlags & DPSET_LOCAL )
2588 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2589 lpCopyDataFrom = lpGData->lpLocalData;
2591 else
2593 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2594 lpCopyDataFrom = lpGData->lpRemoteData;
2597 /* Is the user requesting to know how big a buffer is required? */
2598 if( ( lpData == NULL ) ||
2599 ( *lpdwDataSize < dwRequiredBufferSize )
2602 *lpdwDataSize = dwRequiredBufferSize;
2603 return DPERR_BUFFERTOOSMALL;
2606 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2608 return DP_OK;
2611 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2612 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2613 LPDWORD lpdwDataSize, DWORD dwFlags )
2615 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2616 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2617 dwFlags, TRUE );
2620 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2621 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2622 LPDWORD lpdwDataSize, DWORD dwFlags )
2624 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2625 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2626 dwFlags, FALSE );
2629 static HRESULT DP_IF_GetGroupName
2630 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2631 LPDWORD lpdwDataSize, BOOL bAnsi )
2633 lpGroupData lpGData;
2634 LPDPNAME lpName = lpData;
2635 DWORD dwRequiredDataSize;
2637 FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2638 This, idGroup, lpData, lpdwDataSize, bAnsi );
2640 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2642 return DPERR_INVALIDGROUP;
2645 dwRequiredDataSize = lpGData->name.dwSize;
2647 if( lpGData->name.u1.lpszShortNameA )
2649 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2652 if( lpGData->name.u2.lpszLongNameA )
2654 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2657 if( ( lpData == NULL ) ||
2658 ( *lpdwDataSize < dwRequiredDataSize )
2661 *lpdwDataSize = dwRequiredDataSize;
2662 return DPERR_BUFFERTOOSMALL;
2665 /* Copy the structure */
2666 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2668 if( lpGData->name.u1.lpszShortNameA )
2670 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2671 lpGData->name.u1.lpszShortNameA );
2673 else
2675 lpName->u1.lpszShortNameA = NULL;
2678 if( lpGData->name.u1.lpszShortNameA )
2680 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2681 lpGData->name.u2.lpszLongNameA );
2683 else
2685 lpName->u2.lpszLongNameA = NULL;
2688 return DP_OK;
2691 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2692 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2693 LPDWORD lpdwDataSize )
2695 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2696 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2699 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2700 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2701 LPDWORD lpdwDataSize )
2703 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2704 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2707 static HRESULT DP_IF_GetMessageCount
2708 ( IDirectPlay2Impl* This, DPID idPlayer,
2709 LPDWORD lpdwCount, BOOL bAnsi )
2711 FIXME("(%p)->(0x%08x,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2712 return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2713 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2714 bAnsi );
2717 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2718 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2720 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2721 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2724 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2725 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2727 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2728 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2731 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2732 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2734 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2735 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2736 return DP_OK;
2739 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2740 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2742 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2743 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2744 return DP_OK;
2747 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2748 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2749 DWORD dwFlags )
2751 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2752 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2755 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2756 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2757 DWORD dwFlags )
2759 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2760 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2763 static HRESULT DP_IF_GetPlayerData
2764 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2765 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2767 lpPlayerList lpPList;
2768 DWORD dwRequiredBufferSize;
2769 LPVOID lpCopyDataFrom;
2771 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2772 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2774 if( This->dp2->connectionInitialized == NO_PROVIDER )
2776 return DPERR_UNINITIALIZED;
2779 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2781 return DPERR_INVALIDPLAYER;
2784 if( lpdwDataSize == NULL )
2786 return DPERR_INVALIDPARAMS;
2789 /* How much buffer is required? */
2790 if( dwFlags & DPSET_LOCAL )
2792 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2793 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2795 else
2797 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2798 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2801 /* Is the user requesting to know how big a buffer is required? */
2802 if( ( lpData == NULL ) ||
2803 ( *lpdwDataSize < dwRequiredBufferSize )
2806 *lpdwDataSize = dwRequiredBufferSize;
2807 return DPERR_BUFFERTOOSMALL;
2810 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2812 return DP_OK;
2815 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2816 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2817 LPDWORD lpdwDataSize, DWORD dwFlags )
2819 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2820 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2821 dwFlags, TRUE );
2824 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2825 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2826 LPDWORD lpdwDataSize, DWORD dwFlags )
2828 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2829 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2830 dwFlags, FALSE );
2833 static HRESULT DP_IF_GetPlayerName
2834 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2835 LPDWORD lpdwDataSize, BOOL bAnsi )
2837 lpPlayerList lpPList;
2838 LPDPNAME lpName = lpData;
2839 DWORD dwRequiredDataSize;
2841 FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2842 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2844 if( This->dp2->connectionInitialized == NO_PROVIDER )
2846 return DPERR_UNINITIALIZED;
2849 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2851 return DPERR_INVALIDPLAYER;
2854 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2856 if( lpPList->lpPData->name.u1.lpszShortNameA )
2858 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2861 if( lpPList->lpPData->name.u2.lpszLongNameA )
2863 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2866 if( ( lpData == NULL ) ||
2867 ( *lpdwDataSize < dwRequiredDataSize )
2870 *lpdwDataSize = dwRequiredDataSize;
2871 return DPERR_BUFFERTOOSMALL;
2874 /* Copy the structure */
2875 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2877 if( lpPList->lpPData->name.u1.lpszShortNameA )
2879 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2880 lpPList->lpPData->name.u1.lpszShortNameA );
2882 else
2884 lpName->u1.lpszShortNameA = NULL;
2887 if( lpPList->lpPData->name.u2.lpszLongNameA )
2889 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2890 lpPList->lpPData->name.u2.lpszLongNameA );
2892 else
2894 lpName->u2.lpszLongNameA = NULL;
2897 return DP_OK;
2900 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2901 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2902 LPDWORD lpdwDataSize )
2904 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2905 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2908 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2909 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2910 LPDWORD lpdwDataSize )
2912 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2913 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2916 static HRESULT DP_GetSessionDesc
2917 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2918 BOOL bAnsi )
2920 DWORD dwRequiredSize;
2922 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2924 if( This->dp2->connectionInitialized == NO_PROVIDER )
2926 return DPERR_UNINITIALIZED;
2929 if( !This->dp2->bConnectionOpen )
2931 return DPERR_NOSESSIONS;
2934 if( ( lpdwDataSize == NULL ) || ( *lpdwDataSize >= MAXDWORD ) )
2936 return DPERR_INVALIDPARAMS;
2939 /* FIXME: Get from This->dp2->lpSessionDesc */
2940 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2942 if ( ( lpData == NULL ) ||
2943 ( *lpdwDataSize < dwRequiredSize )
2946 *lpdwDataSize = dwRequiredSize;
2947 return DPERR_BUFFERTOOSMALL;
2950 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2952 return DP_OK;
2955 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2956 ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2958 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2959 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2962 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2963 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2965 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2966 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2969 /* Intended only for COM compatibility. Always returns an error. */
2970 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2971 ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2973 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2974 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2975 return DPERR_ALREADYINITIALIZED;
2978 /* Intended only for COM compatibility. Always returns an error. */
2979 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2980 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2982 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2983 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2984 return DPERR_ALREADYINITIALIZED;
2988 static HRESULT DP_SecureOpen
2989 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2990 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2991 BOOL bAnsi )
2993 HRESULT hr = DP_OK;
2995 FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2996 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2998 if( ( lpsd == NULL ) ||
2999 ( lpsd->dwSize != sizeof(DPSESSIONDESC2) ) )
3001 return DPERR_INVALIDPARAMS;
3004 if( This->dp2->bConnectionOpen )
3006 TRACE( ": rejecting already open connection.\n" );
3007 return DPERR_ALREADYINITIALIZED;
3010 /* If we're enumerating, kill the thread */
3011 DP_KillEnumSessionThread( This );
3013 if( dwFlags & DPOPEN_JOIN )
3015 LPDPSESSIONDESC2 current = NULL;
3016 NS_ResetSessionEnumeration( This->dp2->lpNameServerData );
3017 while( ( current = NS_WalkSessions( This->dp2->lpNameServerData ) ) )
3019 if ( IsEqualGUID( &lpsd->guidInstance, &current->guidInstance ) )
3020 break;
3022 if ( current == NULL )
3023 return DPERR_NOSESSIONS;
3025 else if( dwFlags & DPOPEN_CREATE )
3027 /* Rightoo - this computer is the host and the local computer needs to be
3028 the name server so that others can join this session */
3029 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
3031 This->dp2->bHostInterface = TRUE;
3033 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
3034 if( FAILED( hr ) )
3036 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
3037 return hr;
3041 /* Invoke the conditional callback for the service provider */
3042 if( This->dp2->spData.lpCB->Open )
3044 DPSP_OPENDATA data;
3046 FIXME( "Not all data fields are correct. Need new parameter\n" );
3048 data.bCreate = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
3049 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
3050 : NS_GetNSAddr( This->dp2->lpNameServerData );
3051 data.lpISP = This->dp2->spData.lpISP;
3052 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
3053 data.dwOpenFlags = dwFlags;
3054 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
3056 hr = (*This->dp2->spData.lpCB->Open)(&data);
3057 if( FAILED( hr ) )
3059 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
3060 return hr;
3065 /* Create the system group of which everything is a part of */
3066 DPID systemGroup = DPID_SYSTEM_GROUP;
3068 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
3069 NULL, 0, 0, TRUE );
3073 if( dwFlags & DPOPEN_JOIN )
3075 DPID dpidServerId = DPID_UNKNOWN;
3077 /* Create the server player for this interface. This way we can receive
3078 * messages for this session.
3080 /* FIXME: I suppose that we should be setting an event for a receive
3081 * type of thing. That way the messaging thread could know to wake
3082 * up. DPlay would then trigger the hEvent for the player the
3083 * message is directed to.
3085 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
3087 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
3090 else if( dwFlags & DPOPEN_CREATE )
3092 DPID dpidNameServerId = DPID_NAME_SERVER;
3094 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
3095 0, DPPLAYER_SERVERPLAYER, bAnsi );
3098 if( FAILED(hr) )
3100 ERR( "Couldn't create name server/system player: %s\n",
3101 DPLAYX_HresultToString(hr) );
3103 else
3105 This->dp2->bConnectionOpen = TRUE;
3108 return hr;
3111 static HRESULT WINAPI DirectPlay2AImpl_Open
3112 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
3114 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3115 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
3116 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
3119 static HRESULT WINAPI DirectPlay2WImpl_Open
3120 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
3122 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3123 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
3124 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
3127 static HRESULT DP_IF_Receive
3128 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
3129 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
3131 LPDPMSG lpMsg = NULL;
3133 FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
3134 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
3136 if( This->dp2->connectionInitialized == NO_PROVIDER )
3138 return DPERR_UNINITIALIZED;
3141 if( dwFlags == 0 )
3143 dwFlags = DPRECEIVE_ALL;
3146 /* If the lpData is NULL, we must be peeking the message */
3147 if( ( lpData == NULL ) &&
3148 !( dwFlags & DPRECEIVE_PEEK )
3151 return DPERR_INVALIDPARAMS;
3154 if( dwFlags & DPRECEIVE_ALL )
3156 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
3158 if( !( dwFlags & DPRECEIVE_PEEK ) )
3160 FIXME( "Remove from queue\n" );
3163 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
3164 ( dwFlags & DPRECEIVE_FROMPLAYER )
3167 FIXME( "Find matching message 0x%08x\n", dwFlags );
3169 else
3171 ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
3174 if( lpMsg == NULL )
3176 return DPERR_NOMESSAGES;
3179 /* Copy into the provided buffer */
3180 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
3182 return DP_OK;
3185 static HRESULT WINAPI DirectPlay2AImpl_Receive
3186 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
3187 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3189 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3190 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3191 lpData, lpdwDataSize, TRUE );
3194 static HRESULT WINAPI DirectPlay2WImpl_Receive
3195 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
3196 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3198 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3199 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3200 lpData, lpdwDataSize, FALSE );
3203 static HRESULT WINAPI DirectPlay2AImpl_Send
3204 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3206 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3207 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3208 0, 0, NULL, NULL, TRUE );
3211 static HRESULT WINAPI DirectPlay2WImpl_Send
3212 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3214 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3215 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3216 0, 0, NULL, NULL, FALSE );
3219 static HRESULT DP_IF_SetGroupData
3220 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3221 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3223 lpGroupData lpGData;
3225 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3226 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3228 /* Parameter check */
3229 if( ( lpData == NULL ) &&
3230 ( dwDataSize != 0 )
3233 return DPERR_INVALIDPARAMS;
3236 /* Find the pointer to the data for this player */
3237 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3239 return DPERR_INVALIDOBJECT;
3242 if( !(dwFlags & DPSET_LOCAL) )
3244 FIXME( "Was this group created by this interface?\n" );
3245 /* FIXME: If this is a remote update need to allow it but not
3246 * send a message.
3250 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3252 /* FIXME: Only send a message if this group is local to the session otherwise
3253 * it will have been rejected above
3255 if( !(dwFlags & DPSET_LOCAL) )
3257 FIXME( "Send msg?\n" );
3260 return DP_OK;
3263 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3264 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3265 DWORD dwDataSize, DWORD dwFlags )
3267 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3268 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3271 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3272 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3273 DWORD dwDataSize, DWORD dwFlags )
3275 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3276 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3279 static HRESULT DP_IF_SetGroupName
3280 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3281 DWORD dwFlags, BOOL bAnsi )
3283 lpGroupData lpGData;
3285 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3286 lpGroupName, dwFlags, bAnsi );
3288 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3290 return DPERR_INVALIDGROUP;
3293 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3295 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3296 FIXME( "Message not sent and dwFlags ignored\n" );
3298 return DP_OK;
3301 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3302 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3303 DWORD dwFlags )
3305 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3306 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3309 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3310 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3311 DWORD dwFlags )
3313 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3314 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3317 static HRESULT DP_IF_SetPlayerData
3318 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3319 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3321 lpPlayerList lpPList;
3323 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3324 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3326 if( This->dp2->connectionInitialized == NO_PROVIDER )
3328 return DPERR_UNINITIALIZED;
3331 /* Parameter check */
3332 if( ( ( lpData == NULL ) && ( dwDataSize != 0 ) ) ||
3333 ( dwDataSize >= MAXDWORD ) )
3335 return DPERR_INVALIDPARAMS;
3338 /* Find the pointer to the data for this player */
3339 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3341 return DPERR_INVALIDPLAYER;
3344 if( !(dwFlags & DPSET_LOCAL) )
3346 FIXME( "Was this group created by this interface?\n" );
3347 /* FIXME: If this is a remote update need to allow it but not
3348 * send a message.
3352 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3354 if( !(dwFlags & DPSET_LOCAL) )
3356 FIXME( "Send msg?\n" );
3359 return DP_OK;
3362 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3363 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3364 DWORD dwDataSize, DWORD dwFlags )
3366 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3367 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3368 dwFlags, TRUE );
3371 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3372 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3373 DWORD dwDataSize, DWORD dwFlags )
3375 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3376 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3377 dwFlags, FALSE );
3380 static HRESULT DP_IF_SetPlayerName
3381 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3382 DWORD dwFlags, BOOL bAnsi )
3384 lpPlayerList lpPList;
3386 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3387 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3389 if( This->dp2->connectionInitialized == NO_PROVIDER )
3391 return DPERR_UNINITIALIZED;
3394 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3396 return DPERR_INVALIDGROUP;
3399 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3401 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3402 FIXME( "Message not sent and dwFlags ignored\n" );
3404 return DP_OK;
3407 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3408 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3409 DWORD dwFlags )
3411 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3412 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3415 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3416 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3417 DWORD dwFlags )
3419 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3420 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3423 HRESULT DP_SetSessionDesc
3424 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3425 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3427 DWORD dwRequiredSize;
3428 LPDPSESSIONDESC2 lpTempSessDesc;
3430 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3431 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3433 /* FIXME: Copy into This->dp2->lpSessionDesc */
3434 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3435 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3437 if( lpTempSessDesc == NULL )
3439 return DPERR_OUTOFMEMORY;
3442 /* Free the old */
3443 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3445 This->dp2->lpSessionDesc = lpTempSessDesc;
3446 /* Set the new */
3447 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3448 if( bInitial )
3450 /*Initializing session GUID*/
3451 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3453 /* If this is an external invocation of the interface, we should be
3454 * letting everyone know that things have changed. Otherwise this is
3455 * just an initialization and it doesn't need to be propagated.
3457 if( !bInitial )
3459 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3462 return DP_OK;
3465 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3466 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3468 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3470 if( This->dp2->connectionInitialized == NO_PROVIDER )
3472 return DPERR_UNINITIALIZED;
3475 if( !This->dp2->bConnectionOpen )
3477 return DPERR_NOSESSIONS;
3480 if( dwFlags || (lpSessDesc == NULL) )
3482 return DPERR_INVALIDPARAMS;
3485 /* Illegal combinations of flags */
3486 if ( ( lpSessDesc->dwFlags & DPSESSION_MIGRATEHOST ) &&
3487 ( lpSessDesc->dwFlags & ( DPSESSION_CLIENTSERVER |
3488 DPSESSION_MULTICASTSERVER |
3489 DPSESSION_SECURESERVER ) ) )
3491 return DPERR_INVALIDFLAGS;
3494 /* Only the host is allowed to update the session desc */
3495 if( !This->dp2->bHostInterface )
3497 return DPERR_ACCESSDENIED;
3500 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3503 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3504 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3506 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3508 if( This->dp2->connectionInitialized == NO_PROVIDER )
3510 return DPERR_UNINITIALIZED;
3513 if( !This->dp2->bConnectionOpen )
3515 return DPERR_NOSESSIONS;
3518 if( dwFlags || (lpSessDesc == NULL) )
3520 return DPERR_INVALIDPARAMS;
3523 /* Illegal combinations of flags */
3524 if ( ( lpSessDesc->dwFlags & DPSESSION_MIGRATEHOST ) &&
3525 ( lpSessDesc->dwFlags & ( DPSESSION_CLIENTSERVER |
3526 DPSESSION_MULTICASTSERVER |
3527 DPSESSION_SECURESERVER ) ) )
3529 return DPERR_INVALIDFLAGS;
3532 /* Only the host is allowed to update the session desc */
3533 if( !This->dp2->bHostInterface )
3535 return DPERR_ACCESSDENIED;
3538 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3541 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3542 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3544 DWORD dwSize = 0;
3546 if( lpSessDesc == NULL )
3548 /* Hmmm..don't need any size? */
3549 ERR( "NULL lpSessDesc\n" );
3550 return dwSize;
3553 dwSize += sizeof( *lpSessDesc );
3555 if( bAnsi )
3557 if( lpSessDesc->u1.lpszSessionNameA )
3559 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3562 if( lpSessDesc->u2.lpszPasswordA )
3564 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3567 else /* UNICODE */
3569 if( lpSessDesc->u1.lpszSessionName )
3571 dwSize += sizeof( WCHAR ) *
3572 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3575 if( lpSessDesc->u2.lpszPassword )
3577 dwSize += sizeof( WCHAR ) *
3578 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3582 return dwSize;
3585 /* Assumes that contiguous buffers are already allocated. */
3586 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3587 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3589 BYTE* lpStartOfFreeSpace;
3591 if( lpSessionDest == NULL )
3593 ERR( "NULL lpSessionDest\n" );
3594 return;
3597 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3599 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3601 if( bAnsi )
3603 if( lpSessionSrc->u1.lpszSessionNameA )
3605 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3606 lpSessionDest->u1.lpszSessionNameA );
3607 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3608 lpStartOfFreeSpace +=
3609 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3612 if( lpSessionSrc->u2.lpszPasswordA )
3614 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3615 lpSessionDest->u2.lpszPasswordA );
3616 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3617 lpStartOfFreeSpace +=
3618 lstrlenA( lpSessionDest->u2.lpszPasswordA ) + 1;
3621 else /* UNICODE */
3623 if( lpSessionSrc->u1.lpszSessionName )
3625 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3626 lpSessionDest->u1.lpszSessionName );
3627 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3628 lpStartOfFreeSpace += sizeof(WCHAR) *
3629 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3632 if( lpSessionSrc->u2.lpszPassword )
3634 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3635 lpSessionDest->u2.lpszPassword );
3636 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3637 lpStartOfFreeSpace += sizeof(WCHAR) *
3638 ( lstrlenW( lpSessionDest->u2.lpszPassword ) + 1 );
3644 static HRESULT DP_IF_AddGroupToGroup
3645 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3647 lpGroupData lpGData;
3648 lpGroupList lpNewGList;
3650 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3652 if( This->dp2->connectionInitialized == NO_PROVIDER )
3654 return DPERR_UNINITIALIZED;
3657 if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3659 return DPERR_INVALIDGROUP;
3662 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3664 return DPERR_INVALIDGROUP;
3667 /* Create a player list (ie "shortcut" ) */
3668 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3669 if( lpNewGList == NULL )
3671 return DPERR_CANTADDPLAYER;
3674 /* Add the shortcut */
3675 lpGData->uRef++;
3676 lpNewGList->lpGData = lpGData;
3678 /* Add the player to the list of players for this group */
3679 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3681 /* Send a ADDGROUPTOGROUP message */
3682 FIXME( "Not sending message\n" );
3684 return DP_OK;
3687 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3688 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3690 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3691 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3694 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3695 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3697 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3698 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3701 static HRESULT DP_IF_CreateGroupInGroup
3702 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3703 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3704 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3706 lpGroupData lpGParentData;
3707 lpGroupList lpGList;
3708 lpGroupData lpGData;
3710 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3711 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3712 dwDataSize, dwFlags, bAnsi );
3714 /* Verify that the specified parent is valid */
3715 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3716 idParentGroup ) ) == NULL
3719 return DPERR_INVALIDGROUP;
3722 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3723 dwFlags, idParentGroup, bAnsi );
3725 if( lpGData == NULL )
3727 return DPERR_CANTADDPLAYER; /* yes player not group */
3730 /* Something else is referencing this data */
3731 lpGData->uRef++;
3733 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3735 /* The list has now been inserted into the interface group list. We now
3736 need to put a "shortcut" to this group in the parent group */
3737 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3738 if( lpGList == NULL )
3740 FIXME( "Memory leak\n" );
3741 return DPERR_CANTADDPLAYER; /* yes player not group */
3744 lpGList->lpGData = lpGData;
3746 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3748 /* Let the SP know that we've created this group */
3749 if( This->dp2->spData.lpCB->CreateGroup )
3751 DPSP_CREATEGROUPDATA data;
3753 TRACE( "Calling SP CreateGroup\n" );
3755 data.idGroup = *lpidGroup;
3756 data.dwFlags = dwFlags;
3757 data.lpSPMessageHeader = lpMsgHdr;
3758 data.lpISP = This->dp2->spData.lpISP;
3760 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3763 /* Inform all other peers of the creation of a new group. If there are
3764 * no peers keep this quiet.
3766 if( This->dp2->lpSessionDesc &&
3767 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3769 DPMSG_CREATEPLAYERORGROUP msg;
3771 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3772 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3773 msg.dpId = *lpidGroup;
3774 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3775 msg.lpData = lpData;
3776 msg.dwDataSize = dwDataSize;
3777 msg.dpnName = *lpGroupName;
3779 /* FIXME: Correct to just use send effectively? */
3780 /* FIXME: Should size include data w/ message or just message "header" */
3781 /* FIXME: Check return code */
3782 DP_SendEx( (IDirectPlay2Impl*)This,
3783 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3784 0, 0, NULL, NULL, bAnsi );
3787 return DP_OK;
3790 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3791 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3792 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3793 DWORD dwFlags )
3795 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3797 if( This->dp2->connectionInitialized == NO_PROVIDER )
3799 return DPERR_UNINITIALIZED;
3802 if( lpidGroup == NULL ||
3803 !This->dp2->bConnectionOpen ||
3804 dwDataSize >= MAXDWORD ||
3805 ( lpData == NULL && dwDataSize != 0 ) )
3807 return DPERR_INVALIDPARAMS;
3810 *lpidGroup = DPID_UNKNOWN;
3812 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3813 lpGroupName, lpData, dwDataSize, dwFlags,
3814 TRUE );
3817 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3818 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3819 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3820 DWORD dwFlags )
3822 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3824 if( This->dp2->connectionInitialized == NO_PROVIDER )
3826 return DPERR_UNINITIALIZED;
3829 if( lpidGroup == NULL ||
3830 !This->dp2->bConnectionOpen ||
3831 dwDataSize >= MAXDWORD ||
3832 ( lpData == NULL && dwDataSize != 0 ) )
3834 return DPERR_INVALIDPARAMS;
3837 *lpidGroup = DPID_UNKNOWN;
3839 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3840 lpGroupName, lpData, dwDataSize,
3841 dwFlags, FALSE );
3844 static HRESULT DP_IF_DeleteGroupFromGroup
3845 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3847 lpGroupList lpGList;
3848 lpGroupData lpGParentData;
3850 TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3852 /* Is the parent group valid? */
3853 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3855 return DPERR_INVALIDGROUP;
3858 /* Remove the group from the parent group queue */
3859 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3861 if( lpGList == NULL )
3863 return DPERR_INVALIDGROUP;
3866 /* Decrement the ref count */
3867 lpGList->lpGData->uRef--;
3869 /* Free up the list item */
3870 HeapFree( GetProcessHeap(), 0, lpGList );
3872 /* Should send a DELETEGROUPFROMGROUP message */
3873 FIXME( "message not sent\n" );
3875 return DP_OK;
3878 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3879 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3881 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3882 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3885 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3886 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3888 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3889 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3891 static BOOL DP_BuildCompoundAddr( GUID guidDataType,
3892 LPGUID lpcSpGuid,
3893 LPVOID* lplpAddrBuf,
3894 LPDWORD lpdwBufSize )
3896 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3897 HRESULT hr;
3899 dpCompoundAddress.dwDataSize = sizeof( GUID );
3900 dpCompoundAddress.guidDataType = guidDataType;
3901 dpCompoundAddress.lpData = lpcSpGuid;
3903 *lplpAddrBuf = NULL;
3904 *lpdwBufSize = 0;
3906 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3907 lpdwBufSize, TRUE );
3909 if( hr != DPERR_BUFFERTOOSMALL )
3911 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3912 return FALSE;
3915 /* Now allocate the buffer */
3916 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3917 *lpdwBufSize );
3919 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3920 lpdwBufSize, TRUE );
3921 if( FAILED(hr) )
3923 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3924 return FALSE;
3927 return TRUE;
3930 static HRESULT WINAPI DP_IF_EnumConnections
3931 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication,
3932 LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext,
3933 DWORD dwFlags, BOOL bAnsi )
3935 HKEY hkResult;
3936 WCHAR searchSubKeySP[] = {
3937 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
3938 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
3939 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
3940 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
3941 WCHAR searchSubKeyLP[] = {
3942 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
3943 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
3944 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
3945 'L', 'o', 'b', 'b', 'y', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
3946 WCHAR guidDataSubKey[] = { 'G', 'u', 'i', 'd', 0 };
3947 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
3948 DWORD dwIndex, sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
3949 FILETIME filetime;
3951 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3952 if( dwFlags == 0 )
3954 dwFlags = DPCONNECTION_DIRECTPLAY;
3957 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3958 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) ) )
3960 return DPERR_INVALIDFLAGS;
3963 if( !lpEnumCallback )
3965 return DPERR_INVALIDPARAMS;
3969 /* Need to loop over the service providers in the registry */
3970 if( RegOpenKeyExW( HKEY_LOCAL_MACHINE,
3971 ( dwFlags & DPCONNECTION_DIRECTPLAY ) ? searchSubKeySP
3972 : searchSubKeyLP,
3973 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3975 /* Hmmm. Does this mean that there are no service providers? */
3976 ERR(": no service providers?\n");
3977 return DP_OK;
3981 /* Traverse all the service providers we have available */
3982 for( dwIndex=0;
3983 RegEnumKeyExW( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3984 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3985 ++dwIndex, sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR) )
3987 HKEY hkServiceProvider;
3988 GUID serviceProviderGUID;
3989 WCHAR guidKeyContent[39];
3990 DWORD sizeOfReturnBuffer = sizeof(guidKeyContent);
3991 DPNAME dpName;
3992 BOOL continueEnumeration = TRUE;
3994 LPVOID lpAddressBuffer = NULL;
3995 DWORD dwAddressBufferSize = 0;
3998 TRACE(" this time through: %s\n", debugstr_w(subKeyName) );
4000 /* Get a handle for this particular service provider */
4001 if( RegOpenKeyExW( hkResult, subKeyName, 0, KEY_READ,
4002 &hkServiceProvider ) != ERROR_SUCCESS )
4004 ERR(": what the heck is going on?\n" );
4005 continue;
4008 if( RegQueryValueExW( hkServiceProvider, guidDataSubKey,
4009 NULL, NULL, (LPBYTE)guidKeyContent,
4010 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4012 ERR(": missing GUID registry data members\n" );
4013 RegCloseKey(hkServiceProvider);
4014 continue;
4016 RegCloseKey(hkServiceProvider);
4018 CLSIDFromString( guidKeyContent, &serviceProviderGUID );
4020 /* Fill in the DPNAME struct for the service provider */
4021 dpName.dwSize = sizeof( dpName );
4022 dpName.dwFlags = 0;
4023 if ( bAnsi )
4025 dpName.u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4026 sizeOfSubKeyName+1 );
4027 WideCharToMultiByte( CP_ACP, 0, subKeyName,
4028 -1, dpName.u1.lpszShortNameA, -1, 0, 0);
4029 dpName.u2.lpszLongNameA = NULL;
4031 else
4033 dpName.u1.lpszShortName = subKeyName;
4034 dpName.u2.lpszLongName = NULL;
4037 /* Create the compound address for the service provider.
4038 * NOTE: This is a gruesome architectural scar right now. DP
4039 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
4040 * native dll just gets around this little bit by allocating an
4041 * 80 byte buffer which isn't even filled with a valid compound
4042 * address. Oh well. Creating a proper compound address is the
4043 * way to go anyways despite this method taking slightly more
4044 * heap space and realtime :) */
4046 if ( DP_BuildCompoundAddr( ( ( dwFlags & DPCONNECTION_DIRECTPLAY )
4047 ? DPAID_ServiceProvider
4048 : DPAID_LobbyProvider ),
4049 &serviceProviderGUID,
4050 &lpAddressBuffer,
4051 &dwAddressBufferSize ) )
4053 /* The enumeration will return FALSE if we are not to continue */
4054 continueEnumeration = lpEnumCallback( &serviceProviderGUID, lpAddressBuffer,
4055 dwAddressBufferSize, &dpName,
4056 dwFlags, lpContext );
4058 else
4060 ERR( "Couldn't build compound address\n" );
4063 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4064 if ( bAnsi )
4065 HeapFree( GetProcessHeap(), 0, dpName.u1.lpszShortNameA );
4067 if (!continueEnumeration)
4068 return DP_OK;
4071 return DP_OK;
4074 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
4075 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
4077 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4078 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
4079 return DP_IF_EnumConnections( iface, lpguidApplication, lpEnumCallback, lpContext, dwFlags, TRUE );
4082 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
4083 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
4085 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4086 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
4087 return DP_IF_EnumConnections( iface, lpguidApplication, lpEnumCallback, lpContext, dwFlags, FALSE );
4090 static HRESULT DP_IF_EnumGroupsInGroup
4091 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
4092 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
4093 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
4095 lpGroupList lpGList;
4096 lpGroupData lpGData;
4098 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
4099 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
4100 lpContext, dwFlags, bAnsi );
4102 if( This->dp2->connectionInitialized == NO_PROVIDER )
4104 return DPERR_UNINITIALIZED;
4107 if( !This->dp2->bConnectionOpen )
4109 return DPERR_NOSESSIONS;
4112 if( ( lpEnumPlayersCallback2 == NULL ) ||
4113 ( ( dwFlags & DPENUMGROUPS_SESSION ) && ( lpguidInstance == NULL ) ) )
4115 return DPERR_INVALIDPARAMS;
4118 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4120 return DPERR_INVALIDGROUP;
4123 if( DPQ_IS_EMPTY( lpGData->groups ) )
4125 return DP_OK;
4128 lpGList = DPQ_FIRST( lpGData->groups );
4130 for( ;; )
4132 /* FIXME: Should check dwFlags for match here */
4134 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
4135 &lpGList->lpGData->name, dwFlags,
4136 lpContext ) )
4138 return DP_OK; /* User requested break */
4141 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
4143 break;
4146 lpGList = DPQ_NEXT( lpGList->groups );
4150 return DP_OK;
4153 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
4154 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
4155 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
4156 DWORD dwFlags )
4158 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4159 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
4160 lpEnumPlayersCallback2, lpContext, dwFlags,
4161 TRUE );
4164 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
4165 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
4166 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
4167 DWORD dwFlags )
4169 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4170 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
4171 lpEnumPlayersCallback2, lpContext, dwFlags,
4172 FALSE );
4175 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
4176 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4178 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4179 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4180 return DP_OK;
4183 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
4184 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4186 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4187 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4188 return DP_OK;
4191 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
4192 REFGUID guidDataType,
4193 DWORD dwDataSize,
4194 LPCVOID lpData,
4195 LPVOID lpContext )
4197 /* Looking for the GUID of the provider to load */
4198 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
4199 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
4202 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4203 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
4205 if( dwDataSize != sizeof( GUID ) )
4207 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4210 memcpy( lpContext, lpData, dwDataSize );
4212 /* There shouldn't be more than 1 GUID/compound address */
4213 return FALSE;
4216 /* Still waiting for what we want */
4217 return TRUE;
4221 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4222 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4224 UINT i;
4225 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4226 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4227 LPCSTR guidDataSubKey = "Guid";
4228 LPCSTR majVerDataSubKey = "dwReserved1";
4229 LPCSTR minVerDataSubKey = "dwReserved2";
4230 LPCSTR pathSubKey = "Path";
4232 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4234 /* FIXME: Cloned code with a quick hack. */
4235 for( i=0; i<2; i++ )
4237 HKEY hkResult;
4238 LPCSTR searchSubKey;
4239 char subKeyName[51];
4240 DWORD dwIndex, sizeOfSubKeyName=50;
4241 FILETIME filetime;
4243 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4244 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4247 /* Need to loop over the service providers in the registry */
4248 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4249 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4251 /* Hmmm. Does this mean that there are no service providers? */
4252 ERR(": no service providers?\n");
4253 return 0;
4256 /* Traverse all the service providers we have available */
4257 for( dwIndex=0;
4258 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4259 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4260 ++dwIndex, sizeOfSubKeyName=51 )
4263 HKEY hkServiceProvider;
4264 GUID serviceProviderGUID;
4265 DWORD returnType, sizeOfReturnBuffer = 255;
4266 char returnBuffer[256];
4267 WCHAR buff[51];
4268 DWORD dwTemp, len;
4270 TRACE(" this time through: %s\n", subKeyName );
4272 /* Get a handle for this particular service provider */
4273 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4274 &hkServiceProvider ) != ERROR_SUCCESS )
4276 ERR(": what the heck is going on?\n" );
4277 continue;
4280 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4281 NULL, &returnType, (LPBYTE)returnBuffer,
4282 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4284 ERR(": missing GUID registry data members\n" );
4285 continue;
4288 /* FIXME: Check return types to ensure we're interpreting data right */
4289 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4290 CLSIDFromString( buff, &serviceProviderGUID );
4291 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4293 /* Determine if this is the Service Provider that the user asked for */
4294 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4296 continue;
4299 if( i == 0 ) /* DP SP */
4301 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4302 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4303 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4306 sizeOfReturnBuffer = 255;
4308 /* Get dwReserved1 */
4309 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4310 NULL, &returnType, (LPBYTE)returnBuffer,
4311 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4313 ERR(": missing dwReserved1 registry data members\n") ;
4314 continue;
4317 if( i == 0 )
4318 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4320 sizeOfReturnBuffer = 255;
4322 /* Get dwReserved2 */
4323 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4324 NULL, &returnType, (LPBYTE)returnBuffer,
4325 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4327 ERR(": missing dwReserved1 registry data members\n") ;
4328 continue;
4331 if( i == 0 )
4332 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4334 sizeOfReturnBuffer = 255;
4336 /* Get the path for this service provider */
4337 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4338 NULL, NULL, (LPBYTE)returnBuffer,
4339 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4341 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4342 continue;
4345 TRACE( "Loading %s\n", returnBuffer );
4346 return LoadLibraryA( returnBuffer );
4350 return 0;
4353 static
4354 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4356 HRESULT hr;
4357 LPDPSP_SPINIT SPInit;
4359 /* Initialize the service provider by calling SPInit */
4360 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4362 if( SPInit == NULL )
4364 ERR( "Service provider doesn't provide SPInit interface?\n" );
4365 FreeLibrary( hServiceProvider );
4366 return DPERR_UNAVAILABLE;
4369 TRACE( "Calling SPInit (DP SP entry point)\n" );
4371 hr = (*SPInit)( &This->dp2->spData );
4373 if( FAILED(hr) )
4375 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4376 FreeLibrary( hServiceProvider );
4377 return hr;
4380 /* FIXME: Need to verify the sanity of the returned callback table
4381 * using IsBadCodePtr */
4382 This->dp2->bSPInitialized = TRUE;
4384 /* This interface is now initialized as a DP object */
4385 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4387 /* Store the handle of the module so that we can unload it later */
4388 This->dp2->hServiceProvider = hServiceProvider;
4390 return hr;
4393 static
4394 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4396 HRESULT hr;
4397 LPSP_INIT DPLSPInit;
4399 /* Initialize the service provider by calling SPInit */
4400 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4402 if( DPLSPInit == NULL )
4404 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4405 FreeLibrary( hLobbyProvider );
4406 return DPERR_UNAVAILABLE;
4409 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4411 hr = (*DPLSPInit)( &This->dp2->dplspData );
4413 if( FAILED(hr) )
4415 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4416 FreeLibrary( hLobbyProvider );
4417 return hr;
4420 /* FIXME: Need to verify the sanity of the returned callback table
4421 * using IsBadCodePtr */
4423 This->dp2->bDPLSPInitialized = TRUE;
4425 /* This interface is now initialized as a lobby object */
4426 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4428 /* Store the handle of the module so that we can unload it later */
4429 This->dp2->hDPLobbyProvider = hLobbyProvider;
4431 return hr;
4434 static HRESULT DP_IF_InitializeConnection
4435 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4437 HMODULE hServiceProvider;
4438 HRESULT hr;
4439 GUID guidSP;
4440 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4441 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4443 TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4445 if ( lpConnection == NULL )
4447 return DPERR_INVALIDPARAMS;
4450 if( dwFlags != 0 )
4452 return DPERR_INVALIDFLAGS;
4455 if( This->dp2->connectionInitialized != NO_PROVIDER )
4457 return DPERR_ALREADYINITIALIZED;
4460 /* Find out what the requested SP is and how large this buffer is */
4461 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4462 dwAddrSize, &guidSP );
4464 if( FAILED(hr) )
4466 ERR( "Invalid compound address?\n" );
4467 return DPERR_UNAVAILABLE;
4470 /* Load the service provider */
4471 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4473 if( hServiceProvider == 0 )
4475 ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4476 return DPERR_UNAVAILABLE;
4479 if( bIsDpSp )
4481 /* Fill in what we can of the Service Provider required information.
4482 * The rest was be done in DP_LoadSP
4484 This->dp2->spData.lpAddress = lpConnection;
4485 This->dp2->spData.dwAddressSize = dwAddrSize;
4486 This->dp2->spData.lpGuid = &guidSP;
4488 hr = DP_InitializeDPSP( This, hServiceProvider );
4490 else
4492 This->dp2->dplspData.lpAddress = lpConnection;
4494 hr = DP_InitializeDPLSP( This, hServiceProvider );
4497 if( FAILED(hr) )
4499 return hr;
4502 return DP_OK;
4505 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4506 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4508 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4509 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4512 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4513 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4515 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4516 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4519 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4520 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4521 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4523 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4524 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4527 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4528 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4529 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4531 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4532 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4535 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4536 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4538 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4539 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4540 return DP_OK;
4543 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4544 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4546 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4547 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4548 return DP_OK;
4551 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4552 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4554 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4555 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4556 return DP_OK;
4559 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4560 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4562 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4563 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4564 return DP_OK;
4567 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4568 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4570 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4571 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4572 return DP_OK;
4575 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4576 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4578 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4579 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4580 return DP_OK;
4583 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4584 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4586 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4587 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4588 return DP_OK;
4591 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4592 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4594 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4595 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4596 return DP_OK;
4599 static HRESULT DP_IF_GetGroupParent
4600 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4601 BOOL bAnsi )
4603 lpGroupData lpGData;
4605 TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4607 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4609 return DPERR_INVALIDGROUP;
4612 *lpidGroup = lpGData->dpid;
4614 return DP_OK;
4617 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4618 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4620 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4621 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4623 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4624 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4626 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4627 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4630 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4631 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4633 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4634 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4635 return DP_OK;
4638 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4639 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4641 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4642 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4643 return DP_OK;
4646 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4647 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4649 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4650 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4651 return DP_OK;
4654 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4655 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4657 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4658 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4659 return DP_OK;
4662 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4663 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4665 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4666 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4667 return DP_OK;
4670 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4671 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4673 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4674 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4675 return DP_OK;
4678 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4679 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4681 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4682 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4683 return DP_OK;
4686 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4687 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4689 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4690 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4691 return DP_OK;
4694 static HRESULT DP_SendEx
4695 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4696 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4697 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4699 BOOL bValidDestination = FALSE;
4701 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4702 ": stub\n",
4703 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4704 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4706 if( This->dp2->connectionInitialized == NO_PROVIDER )
4708 return DPERR_UNINITIALIZED;
4711 /* FIXME: Add parameter checking */
4712 /* FIXME: First call to this needs to acquire a message id which will be
4713 * used for multiple sends
4716 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4718 /* Verify that the message is being sent from a valid local player. The
4719 * from player may be anonymous DPID_UNKNOWN
4721 if( idFrom != DPID_UNKNOWN )
4723 if( DP_FindPlayer( This, idFrom ) == NULL )
4725 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4726 return DPERR_INVALIDPLAYER;
4730 /* Verify that the message is being sent to a valid player, group or to
4731 * everyone. If it's valid, send it to those players.
4733 if( idTo == DPID_ALLPLAYERS )
4735 bValidDestination = TRUE;
4737 /* See if SP has the ability to multicast. If so, use it */
4738 if( This->dp2->spData.lpCB->SendToGroupEx )
4740 FIXME( "Use group sendex to group 0\n" );
4742 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4744 FIXME( "Use obsolete group send to group 0\n" );
4746 else /* No multicast, multiplicate */
4748 /* Send to all players we know about */
4749 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4753 if( ( !bValidDestination ) &&
4754 ( DP_FindPlayer( This, idTo ) != NULL )
4757 bValidDestination = TRUE;
4759 /* Have the service provider send this message */
4760 /* FIXME: Could optimize for local interface sends */
4761 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4762 dwTimeout, lpContext, lpdwMsgID );
4765 if( ( !bValidDestination ) &&
4766 ( DP_FindAnyGroup( This, idTo ) != NULL )
4769 bValidDestination = TRUE;
4771 /* See if SP has the ability to multicast. If so, use it */
4772 if( This->dp2->spData.lpCB->SendToGroupEx )
4774 FIXME( "Use group sendex\n" );
4776 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4778 FIXME( "Use obsolete group send to group\n" );
4780 else /* No multicast, multiplicate */
4782 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4785 #if 0
4786 if( bExpectReply )
4788 DWORD dwWaitReturn;
4790 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4792 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4793 if( dwWaitReturn != WAIT_OBJECT_0 )
4795 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4798 #endif
4801 if( !bValidDestination )
4803 return DPERR_INVALIDPLAYER;
4805 else
4807 /* FIXME: Should return what the send returned */
4808 return DP_OK;
4813 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4814 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4815 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4816 LPVOID lpContext, LPDWORD lpdwMsgID )
4818 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4819 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4820 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4823 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4824 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4825 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4826 LPVOID lpContext, LPDWORD lpdwMsgID )
4828 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4829 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4830 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4833 static HRESULT DP_SP_SendEx
4834 ( IDirectPlay2Impl* This, DWORD dwFlags,
4835 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4836 LPVOID lpContext, LPDWORD lpdwMsgID )
4838 LPDPMSG lpMElem;
4840 FIXME( ": stub\n" );
4842 /* FIXME: This queuing should only be for async messages */
4844 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4845 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4847 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4849 /* FIXME: Need to queue based on priority */
4850 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4852 return DP_OK;
4855 static HRESULT DP_IF_GetMessageQueue
4856 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4857 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4859 HRESULT hr = DP_OK;
4861 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4862 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4864 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4865 /* FIXME: What about sends which are not immediate? */
4867 if( This->dp2->spData.lpCB->GetMessageQueue )
4869 DPSP_GETMESSAGEQUEUEDATA data;
4871 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4873 /* FIXME: None of this is documented :( */
4875 data.lpISP = This->dp2->spData.lpISP;
4876 data.dwFlags = dwFlags;
4877 data.idFrom = idFrom;
4878 data.idTo = idTo;
4879 data.lpdwNumMsgs = lpdwNumMsgs;
4880 data.lpdwNumBytes = lpdwNumBytes;
4882 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4884 else
4886 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4889 return hr;
4892 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4893 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4894 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4896 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4897 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4898 lpdwNumBytes, TRUE );
4901 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4902 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4903 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4905 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4906 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4907 lpdwNumBytes, FALSE );
4910 static HRESULT DP_IF_CancelMessage
4911 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4912 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4914 HRESULT hr = DP_OK;
4916 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4917 This, dwMsgID, dwFlags, bAnsi );
4919 if( This->dp2->spData.lpCB->Cancel )
4921 DPSP_CANCELDATA data;
4923 TRACE( "Calling SP Cancel\n" );
4925 /* FIXME: Undocumented callback */
4927 data.lpISP = This->dp2->spData.lpISP;
4928 data.dwFlags = dwFlags;
4929 data.lprglpvSPMsgID = NULL;
4930 data.cSPMsgID = dwMsgID;
4931 data.dwMinPriority = dwMinPriority;
4932 data.dwMaxPriority = dwMaxPriority;
4934 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4936 else
4938 FIXME( "SP doesn't implement Cancel\n" );
4941 return hr;
4944 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4945 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4947 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4949 if( dwFlags != 0 )
4951 return DPERR_INVALIDFLAGS;
4954 if( dwMsgID == 0 )
4956 dwFlags |= DPCANCELSEND_ALL;
4959 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4962 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4963 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4965 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4967 if( dwFlags != 0 )
4969 return DPERR_INVALIDFLAGS;
4972 if( dwMsgID == 0 )
4974 dwFlags |= DPCANCELSEND_ALL;
4977 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4980 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4981 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4982 DWORD dwFlags )
4984 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4986 if( dwFlags != 0 )
4988 return DPERR_INVALIDFLAGS;
4991 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4992 dwMaxPriority, TRUE );
4995 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4996 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4997 DWORD dwFlags )
4999 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
5001 if( dwFlags != 0 )
5003 return DPERR_INVALIDFLAGS;
5006 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
5007 dwMaxPriority, FALSE );
5010 /* Note: Hack so we can reuse the old functions without compiler warnings */
5011 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5012 # define XCAST(fun) (typeof(directPlay2WVT.fun))
5013 #else
5014 # define XCAST(fun) (void*)
5015 #endif
5017 static const IDirectPlay2Vtbl directPlay2WVT =
5019 XCAST(QueryInterface)DP_QueryInterface,
5020 XCAST(AddRef)DP_AddRef,
5021 XCAST(Release)DP_Release,
5023 DirectPlay2WImpl_AddPlayerToGroup,
5024 DirectPlay2WImpl_Close,
5025 DirectPlay2WImpl_CreateGroup,
5026 DirectPlay2WImpl_CreatePlayer,
5027 DirectPlay2WImpl_DeletePlayerFromGroup,
5028 DirectPlay2WImpl_DestroyGroup,
5029 DirectPlay2WImpl_DestroyPlayer,
5030 DirectPlay2WImpl_EnumGroupPlayers,
5031 DirectPlay2WImpl_EnumGroups,
5032 DirectPlay2WImpl_EnumPlayers,
5033 DirectPlay2WImpl_EnumSessions,
5034 DirectPlay2WImpl_GetCaps,
5035 DirectPlay2WImpl_GetGroupData,
5036 DirectPlay2WImpl_GetGroupName,
5037 DirectPlay2WImpl_GetMessageCount,
5038 DirectPlay2WImpl_GetPlayerAddress,
5039 DirectPlay2WImpl_GetPlayerCaps,
5040 DirectPlay2WImpl_GetPlayerData,
5041 DirectPlay2WImpl_GetPlayerName,
5042 DirectPlay2WImpl_GetSessionDesc,
5043 DirectPlay2WImpl_Initialize,
5044 DirectPlay2WImpl_Open,
5045 DirectPlay2WImpl_Receive,
5046 DirectPlay2WImpl_Send,
5047 DirectPlay2WImpl_SetGroupData,
5048 DirectPlay2WImpl_SetGroupName,
5049 DirectPlay2WImpl_SetPlayerData,
5050 DirectPlay2WImpl_SetPlayerName,
5051 DirectPlay2WImpl_SetSessionDesc
5053 #undef XCAST
5055 /* Note: Hack so we can reuse the old functions without compiler warnings */
5056 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5057 # define XCAST(fun) (typeof(directPlay2AVT.fun))
5058 #else
5059 # define XCAST(fun) (void*)
5060 #endif
5062 static const IDirectPlay2Vtbl directPlay2AVT =
5064 XCAST(QueryInterface)DP_QueryInterface,
5065 XCAST(AddRef)DP_AddRef,
5066 XCAST(Release)DP_Release,
5068 DirectPlay2AImpl_AddPlayerToGroup,
5069 DirectPlay2AImpl_Close,
5070 DirectPlay2AImpl_CreateGroup,
5071 DirectPlay2AImpl_CreatePlayer,
5072 DirectPlay2AImpl_DeletePlayerFromGroup,
5073 DirectPlay2AImpl_DestroyGroup,
5074 DirectPlay2AImpl_DestroyPlayer,
5075 DirectPlay2AImpl_EnumGroupPlayers,
5076 DirectPlay2AImpl_EnumGroups,
5077 DirectPlay2AImpl_EnumPlayers,
5078 DirectPlay2AImpl_EnumSessions,
5079 DirectPlay2AImpl_GetCaps,
5080 DirectPlay2AImpl_GetGroupData,
5081 DirectPlay2AImpl_GetGroupName,
5082 DirectPlay2AImpl_GetMessageCount,
5083 DirectPlay2AImpl_GetPlayerAddress,
5084 DirectPlay2AImpl_GetPlayerCaps,
5085 DirectPlay2AImpl_GetPlayerData,
5086 DirectPlay2AImpl_GetPlayerName,
5087 DirectPlay2AImpl_GetSessionDesc,
5088 DirectPlay2AImpl_Initialize,
5089 DirectPlay2AImpl_Open,
5090 DirectPlay2AImpl_Receive,
5091 DirectPlay2AImpl_Send,
5092 DirectPlay2AImpl_SetGroupData,
5093 DirectPlay2AImpl_SetGroupName,
5094 DirectPlay2AImpl_SetPlayerData,
5095 DirectPlay2AImpl_SetPlayerName,
5096 DirectPlay2AImpl_SetSessionDesc
5098 #undef XCAST
5101 /* Note: Hack so we can reuse the old functions without compiler warnings */
5102 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5103 # define XCAST(fun) (typeof(directPlay3AVT.fun))
5104 #else
5105 # define XCAST(fun) (void*)
5106 #endif
5108 static const IDirectPlay3Vtbl directPlay3AVT =
5110 XCAST(QueryInterface)DP_QueryInterface,
5111 XCAST(AddRef)DP_AddRef,
5112 XCAST(Release)DP_Release,
5114 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5115 XCAST(Close)DirectPlay2AImpl_Close,
5116 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5117 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5118 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5119 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5120 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5121 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5122 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5123 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5124 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5125 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5126 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5127 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5128 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5129 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5130 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5131 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5132 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5133 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5134 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5135 XCAST(Open)DirectPlay2AImpl_Open,
5136 XCAST(Receive)DirectPlay2AImpl_Receive,
5137 XCAST(Send)DirectPlay2AImpl_Send,
5138 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5139 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5140 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5141 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5142 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5144 DirectPlay3AImpl_AddGroupToGroup,
5145 DirectPlay3AImpl_CreateGroupInGroup,
5146 DirectPlay3AImpl_DeleteGroupFromGroup,
5147 DirectPlay3AImpl_EnumConnections,
5148 DirectPlay3AImpl_EnumGroupsInGroup,
5149 DirectPlay3AImpl_GetGroupConnectionSettings,
5150 DirectPlay3AImpl_InitializeConnection,
5151 DirectPlay3AImpl_SecureOpen,
5152 DirectPlay3AImpl_SendChatMessage,
5153 DirectPlay3AImpl_SetGroupConnectionSettings,
5154 DirectPlay3AImpl_StartSession,
5155 DirectPlay3AImpl_GetGroupFlags,
5156 DirectPlay3AImpl_GetGroupParent,
5157 DirectPlay3AImpl_GetPlayerAccount,
5158 DirectPlay3AImpl_GetPlayerFlags
5160 #undef XCAST
5162 /* Note: Hack so we can reuse the old functions without compiler warnings */
5163 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5164 # define XCAST(fun) (typeof(directPlay3WVT.fun))
5165 #else
5166 # define XCAST(fun) (void*)
5167 #endif
5168 static const IDirectPlay3Vtbl directPlay3WVT =
5170 XCAST(QueryInterface)DP_QueryInterface,
5171 XCAST(AddRef)DP_AddRef,
5172 XCAST(Release)DP_Release,
5174 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5175 XCAST(Close)DirectPlay2WImpl_Close,
5176 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5177 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5178 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5179 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5180 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5181 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5182 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5183 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5184 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5185 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5186 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5187 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5188 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5189 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5190 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5191 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5192 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5193 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5194 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5195 XCAST(Open)DirectPlay2WImpl_Open,
5196 XCAST(Receive)DirectPlay2WImpl_Receive,
5197 XCAST(Send)DirectPlay2WImpl_Send,
5198 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5199 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5200 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5201 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5202 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5204 DirectPlay3WImpl_AddGroupToGroup,
5205 DirectPlay3WImpl_CreateGroupInGroup,
5206 DirectPlay3WImpl_DeleteGroupFromGroup,
5207 DirectPlay3WImpl_EnumConnections,
5208 DirectPlay3WImpl_EnumGroupsInGroup,
5209 DirectPlay3WImpl_GetGroupConnectionSettings,
5210 DirectPlay3WImpl_InitializeConnection,
5211 DirectPlay3WImpl_SecureOpen,
5212 DirectPlay3WImpl_SendChatMessage,
5213 DirectPlay3WImpl_SetGroupConnectionSettings,
5214 DirectPlay3WImpl_StartSession,
5215 DirectPlay3WImpl_GetGroupFlags,
5216 DirectPlay3WImpl_GetGroupParent,
5217 DirectPlay3WImpl_GetPlayerAccount,
5218 DirectPlay3WImpl_GetPlayerFlags
5220 #undef XCAST
5222 /* Note: Hack so we can reuse the old functions without compiler warnings */
5223 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5224 # define XCAST(fun) (typeof(directPlay4WVT.fun))
5225 #else
5226 # define XCAST(fun) (void*)
5227 #endif
5228 static const IDirectPlay4Vtbl directPlay4WVT =
5230 XCAST(QueryInterface)DP_QueryInterface,
5231 XCAST(AddRef)DP_AddRef,
5232 XCAST(Release)DP_Release,
5234 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5235 XCAST(Close)DirectPlay2WImpl_Close,
5236 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5237 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5238 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5239 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5240 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5241 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5242 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5243 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5244 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5245 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5246 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5247 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5248 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5249 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5250 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5251 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5252 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5253 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5254 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5255 XCAST(Open)DirectPlay2WImpl_Open,
5256 XCAST(Receive)DirectPlay2WImpl_Receive,
5257 XCAST(Send)DirectPlay2WImpl_Send,
5258 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5259 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5260 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5261 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5262 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5264 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5265 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5266 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5267 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5268 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5269 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5270 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5271 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5272 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5273 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5274 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5275 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5276 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5277 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5278 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5280 DirectPlay4WImpl_GetGroupOwner,
5281 DirectPlay4WImpl_SetGroupOwner,
5282 DirectPlay4WImpl_SendEx,
5283 DirectPlay4WImpl_GetMessageQueue,
5284 DirectPlay4WImpl_CancelMessage,
5285 DirectPlay4WImpl_CancelPriority
5287 #undef XCAST
5290 /* Note: Hack so we can reuse the old functions without compiler warnings */
5291 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5292 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5293 #else
5294 # define XCAST(fun) (void*)
5295 #endif
5296 static const IDirectPlay4Vtbl directPlay4AVT =
5298 XCAST(QueryInterface)DP_QueryInterface,
5299 XCAST(AddRef)DP_AddRef,
5300 XCAST(Release)DP_Release,
5302 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5303 XCAST(Close)DirectPlay2AImpl_Close,
5304 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5305 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5306 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5307 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5308 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5309 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5310 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5311 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5312 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5313 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5314 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5315 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5316 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5317 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5318 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5319 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5320 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5321 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5322 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5323 XCAST(Open)DirectPlay2AImpl_Open,
5324 XCAST(Receive)DirectPlay2AImpl_Receive,
5325 XCAST(Send)DirectPlay2AImpl_Send,
5326 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5327 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5328 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5329 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5330 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5332 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5333 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5334 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5335 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5336 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5337 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5338 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5339 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5340 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5341 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5342 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5343 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5344 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5345 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5346 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5348 DirectPlay4AImpl_GetGroupOwner,
5349 DirectPlay4AImpl_SetGroupOwner,
5350 DirectPlay4AImpl_SendEx,
5351 DirectPlay4AImpl_GetMessageQueue,
5352 DirectPlay4AImpl_CancelMessage,
5353 DirectPlay4AImpl_CancelPriority
5355 #undef XCAST
5357 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5358 DPID idPlayer,
5359 LPVOID* lplpData )
5361 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5363 if( lpPlayer == NULL )
5365 return DPERR_INVALIDPLAYER;
5368 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5370 return DP_OK;
5373 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5374 DPID idPlayer,
5375 LPVOID lpData )
5377 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5379 if( lpPlayer == NULL )
5381 return DPERR_INVALIDPLAYER;
5384 lpPlayer->lpPData->lpSPPlayerData = lpData;
5386 return DP_OK;
5389 /***************************************************************************
5390 * DirectPlayEnumerateAW
5392 * The pointer to the structure lpContext will be filled with the
5393 * appropriate data for each service offered by the OS. These services are
5394 * not necessarily available on this particular machine but are defined
5395 * as simple service providers under the "Service Providers" registry key.
5396 * This structure is then passed to lpEnumCallback for each of the different
5397 * services.
5399 * This API is useful only for applications written using DirectX3 or
5400 * worse. It is superseded by IDirectPlay3::EnumConnections which also
5401 * gives information on the actual connections.
5403 * defn of a service provider:
5404 * A dynamic-link library used by DirectPlay to communicate over a network.
5405 * The service provider contains all the network-specific code required
5406 * to send and receive messages. Online services and network operators can
5407 * supply service providers to use specialized hardware, protocols, communications
5408 * media, and network resources.
5411 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5412 LPDPENUMDPCALLBACKW lpEnumCallbackW,
5413 LPVOID lpContext)
5415 HKEY hkResult;
5416 static const WCHAR searchSubKey[] = {
5417 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5418 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5419 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5420 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5421 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5422 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5424 DWORD dwIndex;
5425 FILETIME filetime;
5427 char *descriptionA = NULL;
5428 DWORD max_sizeOfDescriptionA = 0;
5429 WCHAR *descriptionW = NULL;
5430 DWORD max_sizeOfDescriptionW = 0;
5432 if (!lpEnumCallbackA && !lpEnumCallbackW)
5434 return DPERR_INVALIDPARAMS;
5437 /* Need to loop over the service providers in the registry */
5438 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5439 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5441 /* Hmmm. Does this mean that there are no service providers? */
5442 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5443 return DPERR_GENERIC;
5446 /* Traverse all the service providers we have available */
5447 dwIndex = 0;
5448 while (1)
5450 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5451 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5452 HKEY hkServiceProvider;
5453 GUID serviceProviderGUID;
5454 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5455 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5456 LONG ret_value;
5458 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5459 NULL, NULL, NULL, &filetime);
5460 if (ret_value == ERROR_NO_MORE_ITEMS)
5461 break;
5462 else if (ret_value != ERROR_SUCCESS)
5464 ERR(": could not enumerate on service provider key.\n");
5465 return DPERR_EXCEPTION;
5467 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5469 /* Open the key for this service provider */
5470 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5472 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5473 continue;
5476 /* Get the GUID from the registry */
5477 if (RegQueryValueExW(hkServiceProvider, guidKey,
5478 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5480 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5481 continue;
5483 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5485 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5486 continue;
5488 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5490 /* The enumeration will return FALSE if we are not to continue.
5492 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5493 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5494 * I think that it simply means that they are in-line with DirectX 6.0
5496 if (lpEnumCallbackA)
5498 DWORD sizeOfDescription = 0;
5500 /* Note that this is the A case of this function, so use the A variant to get the description string */
5501 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5502 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5504 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5505 continue;
5507 if (sizeOfDescription > max_sizeOfDescriptionA)
5509 HeapFree(GetProcessHeap(), 0, descriptionA);
5510 max_sizeOfDescriptionA = sizeOfDescription;
5512 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5513 RegQueryValueExA(hkServiceProvider, "DescriptionA",
5514 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5516 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5517 goto end;
5519 else
5521 DWORD sizeOfDescription = 0;
5523 if (RegQueryValueExW(hkServiceProvider, descW,
5524 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5526 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5527 continue;
5529 if (sizeOfDescription > max_sizeOfDescriptionW)
5531 HeapFree(GetProcessHeap(), 0, descriptionW);
5532 max_sizeOfDescriptionW = sizeOfDescription;
5534 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5535 RegQueryValueExW(hkServiceProvider, descW,
5536 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5538 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5539 goto end;
5542 dwIndex++;
5545 end:
5546 HeapFree(GetProcessHeap(), 0, descriptionA);
5547 HeapFree(GetProcessHeap(), 0, descriptionW);
5549 return DP_OK;
5552 /***************************************************************************
5553 * DirectPlayEnumerate [DPLAYX.9]
5554 * DirectPlayEnumerateA [DPLAYX.2]
5556 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5558 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5560 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5563 /***************************************************************************
5564 * DirectPlayEnumerateW [DPLAYX.3]
5566 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5568 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5570 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5573 typedef struct tagCreateEnum
5575 LPVOID lpConn;
5576 LPCGUID lpGuid;
5577 } CreateEnumData, *lpCreateEnumData;
5579 /* Find and copy the matching connection for the SP guid */
5580 static BOOL CALLBACK cbDPCreateEnumConnections(
5581 LPCGUID lpguidSP,
5582 LPVOID lpConnection,
5583 DWORD dwConnectionSize,
5584 LPCDPNAME lpName,
5585 DWORD dwFlags,
5586 LPVOID lpContext)
5588 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5590 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5592 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5594 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5595 dwConnectionSize );
5596 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5598 /* Found the record that we were looking for */
5599 return FALSE;
5602 /* Haven't found what were looking for yet */
5603 return TRUE;
5607 /***************************************************************************
5608 * DirectPlayCreate [DPLAYX.1]
5611 HRESULT WINAPI DirectPlayCreate
5612 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5614 HRESULT hr;
5615 LPDIRECTPLAY3A lpDP3A;
5616 CreateEnumData cbData;
5618 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5620 if( pUnk != NULL )
5622 return CLASS_E_NOAGGREGATION;
5625 if( (lplpDP == NULL) || (lpGUID == NULL) )
5627 return DPERR_INVALIDPARAMS;
5631 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5632 give them an IDirectPlay2A object and hope that doesn't cause problems */
5633 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5635 return DPERR_UNAVAILABLE;
5638 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5640 /* The GUID_NULL means don't bind a service provider. Just return the
5641 interface as is */
5642 return DP_OK;
5645 /* Bind the desired service provider since lpGUID is non NULL */
5646 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5648 /* We're going to use a DP3 interface */
5649 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5650 (LPVOID*)&lpDP3A );
5651 if( FAILED(hr) )
5653 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5654 return hr;
5657 cbData.lpConn = NULL;
5658 cbData.lpGuid = lpGUID;
5660 /* We were given a service provider, find info about it... */
5661 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5662 &cbData, DPCONNECTION_DIRECTPLAY );
5663 if( ( FAILED(hr) ) ||
5664 ( cbData.lpConn == NULL )
5667 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5668 IDirectPlayX_Release( lpDP3A );
5669 return DPERR_UNAVAILABLE;
5672 /* Initialize the service provider */
5673 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5674 if( FAILED(hr) )
5676 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5677 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5678 IDirectPlayX_Release( lpDP3A );
5679 return hr;
5682 /* Release our version of the interface now that we're done with it */
5683 IDirectPlayX_Release( lpDP3A );
5684 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5686 return DP_OK;