dplayx: Modified FP_IF_Receive to actually do something useful
[wine/gsoc_dplay.git] / dlls / dplayx / dplay.c
blobef52b29826d10293b8e52e65f2638b50ebc81054
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 ( ( lpdwDataSize == NULL ) ||
3142 ( ( dwFlags & DPRECEIVE_FROMPLAYER ) && ( lpidFrom == NULL ) ) ||
3143 ( ( dwFlags & DPRECEIVE_TOPLAYER ) && ( lpidTo == NULL ) ) )
3145 return DPERR_INVALIDPARAMS;
3148 if( dwFlags == 0 )
3150 dwFlags = DPRECEIVE_ALL;
3153 if( dwFlags & DPRECEIVE_ALL )
3155 lpMsg = DPQ_FIRST( This->dp2->receiveMsgs );
3157 else
3159 if ( (lpMsg = DPQ_FIRST( This->dp2->receiveMsgs )) )
3163 if ( ( ( dwFlags & DPRECEIVE_FROMPLAYER ) &&
3164 ( dwFlags & DPRECEIVE_TOPLAYER ) &&
3165 ( lpMsg->idFrom == *lpidFrom ) &&
3166 ( lpMsg->idTo == *lpidTo ) ) || /* From & To */
3167 ( ( dwFlags & DPRECEIVE_FROMPLAYER ) &&
3168 ( lpMsg->idFrom == *lpidFrom ) ) || /* From */
3169 ( ( dwFlags & DPRECEIVE_TOPLAYER ) &&
3170 ( lpMsg->idTo == *lpidTo ) ) ) /* To */
3172 break;
3175 while( (lpMsg = DPQ_NEXT( lpMsg->msgs )) );
3179 if( lpMsg == NULL )
3181 return DPERR_NOMESSAGES;
3184 /* Buffer size check */
3185 if ( ( lpData == NULL ) ||
3186 ( *lpdwDataSize < lpMsg->dwMsgSize ) )
3188 *lpdwDataSize = lpMsg->dwMsgSize;
3189 return DPERR_BUFFERTOOSMALL;
3192 /* Copy into the provided buffer */
3193 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
3195 /* Set players */
3196 if ( lpidFrom )
3198 *lpidFrom = lpMsg->idFrom;
3200 if ( lpidTo )
3202 *lpidTo = lpMsg->idTo;
3205 /* Remove message from queue */
3206 if( !( dwFlags & DPRECEIVE_PEEK ) )
3208 HeapFree( GetProcessHeap(), 0, lpMsg->msg );
3209 DPQ_REMOVE( This->dp2->receiveMsgs, lpMsg, msgs );
3210 HeapFree( GetProcessHeap(), 0, lpMsg );
3213 return DP_OK;
3216 static HRESULT WINAPI DirectPlay2AImpl_Receive
3217 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
3218 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3220 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3221 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3222 lpData, lpdwDataSize, TRUE );
3225 static HRESULT WINAPI DirectPlay2WImpl_Receive
3226 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
3227 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3229 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3230 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3231 lpData, lpdwDataSize, FALSE );
3234 static HRESULT WINAPI DirectPlay2AImpl_Send
3235 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3237 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3238 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3239 0, 0, NULL, NULL, TRUE );
3242 static HRESULT WINAPI DirectPlay2WImpl_Send
3243 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3245 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3246 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3247 0, 0, NULL, NULL, FALSE );
3250 static HRESULT DP_IF_SetGroupData
3251 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3252 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3254 lpGroupData lpGData;
3256 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3257 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3259 /* Parameter check */
3260 if( ( lpData == NULL ) &&
3261 ( dwDataSize != 0 )
3264 return DPERR_INVALIDPARAMS;
3267 /* Find the pointer to the data for this player */
3268 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3270 return DPERR_INVALIDOBJECT;
3273 if( !(dwFlags & DPSET_LOCAL) )
3275 FIXME( "Was this group created by this interface?\n" );
3276 /* FIXME: If this is a remote update need to allow it but not
3277 * send a message.
3281 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3283 /* FIXME: Only send a message if this group is local to the session otherwise
3284 * it will have been rejected above
3286 if( !(dwFlags & DPSET_LOCAL) )
3288 FIXME( "Send msg?\n" );
3291 return DP_OK;
3294 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3295 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3296 DWORD dwDataSize, DWORD dwFlags )
3298 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3299 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3302 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3303 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3304 DWORD dwDataSize, DWORD dwFlags )
3306 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3307 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3310 static HRESULT DP_IF_SetGroupName
3311 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3312 DWORD dwFlags, BOOL bAnsi )
3314 lpGroupData lpGData;
3316 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3317 lpGroupName, dwFlags, bAnsi );
3319 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3321 return DPERR_INVALIDGROUP;
3324 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3326 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3327 FIXME( "Message not sent and dwFlags ignored\n" );
3329 return DP_OK;
3332 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3333 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3334 DWORD dwFlags )
3336 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3337 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3340 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3341 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3342 DWORD dwFlags )
3344 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3345 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3348 static HRESULT DP_IF_SetPlayerData
3349 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3350 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3352 lpPlayerList lpPList;
3354 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3355 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3357 if( This->dp2->connectionInitialized == NO_PROVIDER )
3359 return DPERR_UNINITIALIZED;
3362 /* Parameter check */
3363 if( ( ( lpData == NULL ) && ( dwDataSize != 0 ) ) ||
3364 ( dwDataSize >= MAXDWORD ) )
3366 return DPERR_INVALIDPARAMS;
3369 /* Find the pointer to the data for this player */
3370 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3372 return DPERR_INVALIDPLAYER;
3375 if( !(dwFlags & DPSET_LOCAL) )
3377 FIXME( "Was this group created by this interface?\n" );
3378 /* FIXME: If this is a remote update need to allow it but not
3379 * send a message.
3383 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3385 if( !(dwFlags & DPSET_LOCAL) )
3387 FIXME( "Send msg?\n" );
3390 return DP_OK;
3393 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3394 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3395 DWORD dwDataSize, DWORD dwFlags )
3397 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3398 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3399 dwFlags, TRUE );
3402 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3403 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3404 DWORD dwDataSize, DWORD dwFlags )
3406 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3407 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3408 dwFlags, FALSE );
3411 static HRESULT DP_IF_SetPlayerName
3412 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3413 DWORD dwFlags, BOOL bAnsi )
3415 lpPlayerList lpPList;
3417 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3418 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3420 if( This->dp2->connectionInitialized == NO_PROVIDER )
3422 return DPERR_UNINITIALIZED;
3425 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3427 return DPERR_INVALIDGROUP;
3430 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3432 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3433 FIXME( "Message not sent and dwFlags ignored\n" );
3435 return DP_OK;
3438 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3439 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3440 DWORD dwFlags )
3442 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3443 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3446 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3447 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3448 DWORD dwFlags )
3450 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3451 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3454 HRESULT DP_SetSessionDesc
3455 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3456 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3458 DWORD dwRequiredSize;
3459 LPDPSESSIONDESC2 lpTempSessDesc;
3461 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3462 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3464 /* FIXME: Copy into This->dp2->lpSessionDesc */
3465 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3466 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3468 if( lpTempSessDesc == NULL )
3470 return DPERR_OUTOFMEMORY;
3473 /* Free the old */
3474 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3476 This->dp2->lpSessionDesc = lpTempSessDesc;
3477 /* Set the new */
3478 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3479 if( bInitial )
3481 /*Initializing session GUID*/
3482 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3484 /* If this is an external invocation of the interface, we should be
3485 * letting everyone know that things have changed. Otherwise this is
3486 * just an initialization and it doesn't need to be propagated.
3488 if( !bInitial )
3490 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3493 return DP_OK;
3496 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3497 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3499 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3501 if( This->dp2->connectionInitialized == NO_PROVIDER )
3503 return DPERR_UNINITIALIZED;
3506 if( !This->dp2->bConnectionOpen )
3508 return DPERR_NOSESSIONS;
3511 if( dwFlags || (lpSessDesc == NULL) )
3513 return DPERR_INVALIDPARAMS;
3516 /* Illegal combinations of flags */
3517 if ( ( lpSessDesc->dwFlags & DPSESSION_MIGRATEHOST ) &&
3518 ( lpSessDesc->dwFlags & ( DPSESSION_CLIENTSERVER |
3519 DPSESSION_MULTICASTSERVER |
3520 DPSESSION_SECURESERVER ) ) )
3522 return DPERR_INVALIDFLAGS;
3525 /* Only the host is allowed to update the session desc */
3526 if( !This->dp2->bHostInterface )
3528 return DPERR_ACCESSDENIED;
3531 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3534 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3535 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3537 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3539 if( This->dp2->connectionInitialized == NO_PROVIDER )
3541 return DPERR_UNINITIALIZED;
3544 if( !This->dp2->bConnectionOpen )
3546 return DPERR_NOSESSIONS;
3549 if( dwFlags || (lpSessDesc == NULL) )
3551 return DPERR_INVALIDPARAMS;
3554 /* Illegal combinations of flags */
3555 if ( ( lpSessDesc->dwFlags & DPSESSION_MIGRATEHOST ) &&
3556 ( lpSessDesc->dwFlags & ( DPSESSION_CLIENTSERVER |
3557 DPSESSION_MULTICASTSERVER |
3558 DPSESSION_SECURESERVER ) ) )
3560 return DPERR_INVALIDFLAGS;
3563 /* Only the host is allowed to update the session desc */
3564 if( !This->dp2->bHostInterface )
3566 return DPERR_ACCESSDENIED;
3569 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3572 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3573 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3575 DWORD dwSize = 0;
3577 if( lpSessDesc == NULL )
3579 /* Hmmm..don't need any size? */
3580 ERR( "NULL lpSessDesc\n" );
3581 return dwSize;
3584 dwSize += sizeof( *lpSessDesc );
3586 if( bAnsi )
3588 if( lpSessDesc->u1.lpszSessionNameA )
3590 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3593 if( lpSessDesc->u2.lpszPasswordA )
3595 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3598 else /* UNICODE */
3600 if( lpSessDesc->u1.lpszSessionName )
3602 dwSize += sizeof( WCHAR ) *
3603 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3606 if( lpSessDesc->u2.lpszPassword )
3608 dwSize += sizeof( WCHAR ) *
3609 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3613 return dwSize;
3616 /* Assumes that contiguous buffers are already allocated. */
3617 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3618 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3620 BYTE* lpStartOfFreeSpace;
3622 if( lpSessionDest == NULL )
3624 ERR( "NULL lpSessionDest\n" );
3625 return;
3628 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3630 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3632 if( bAnsi )
3634 if( lpSessionSrc->u1.lpszSessionNameA )
3636 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3637 lpSessionDest->u1.lpszSessionNameA );
3638 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3639 lpStartOfFreeSpace +=
3640 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3643 if( lpSessionSrc->u2.lpszPasswordA )
3645 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3646 lpSessionDest->u2.lpszPasswordA );
3647 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3648 lpStartOfFreeSpace +=
3649 lstrlenA( lpSessionDest->u2.lpszPasswordA ) + 1;
3652 else /* UNICODE */
3654 if( lpSessionSrc->u1.lpszSessionName )
3656 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3657 lpSessionDest->u1.lpszSessionName );
3658 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3659 lpStartOfFreeSpace += sizeof(WCHAR) *
3660 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3663 if( lpSessionSrc->u2.lpszPassword )
3665 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3666 lpSessionDest->u2.lpszPassword );
3667 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3668 lpStartOfFreeSpace += sizeof(WCHAR) *
3669 ( lstrlenW( lpSessionDest->u2.lpszPassword ) + 1 );
3675 static HRESULT DP_IF_AddGroupToGroup
3676 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3678 lpGroupData lpGData;
3679 lpGroupList lpNewGList;
3681 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3683 if( This->dp2->connectionInitialized == NO_PROVIDER )
3685 return DPERR_UNINITIALIZED;
3688 if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3690 return DPERR_INVALIDGROUP;
3693 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3695 return DPERR_INVALIDGROUP;
3698 /* Create a player list (ie "shortcut" ) */
3699 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3700 if( lpNewGList == NULL )
3702 return DPERR_CANTADDPLAYER;
3705 /* Add the shortcut */
3706 lpGData->uRef++;
3707 lpNewGList->lpGData = lpGData;
3709 /* Add the player to the list of players for this group */
3710 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3712 /* Send a ADDGROUPTOGROUP message */
3713 FIXME( "Not sending message\n" );
3715 return DP_OK;
3718 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3719 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3721 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3722 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3725 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3726 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3728 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3729 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3732 static HRESULT DP_IF_CreateGroupInGroup
3733 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3734 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3735 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3737 lpGroupData lpGParentData;
3738 lpGroupList lpGList;
3739 lpGroupData lpGData;
3741 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3742 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3743 dwDataSize, dwFlags, bAnsi );
3745 /* Verify that the specified parent is valid */
3746 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3747 idParentGroup ) ) == NULL
3750 return DPERR_INVALIDGROUP;
3753 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3754 dwFlags, idParentGroup, bAnsi );
3756 if( lpGData == NULL )
3758 return DPERR_CANTADDPLAYER; /* yes player not group */
3761 /* Something else is referencing this data */
3762 lpGData->uRef++;
3764 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3766 /* The list has now been inserted into the interface group list. We now
3767 need to put a "shortcut" to this group in the parent group */
3768 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3769 if( lpGList == NULL )
3771 FIXME( "Memory leak\n" );
3772 return DPERR_CANTADDPLAYER; /* yes player not group */
3775 lpGList->lpGData = lpGData;
3777 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3779 /* Let the SP know that we've created this group */
3780 if( This->dp2->spData.lpCB->CreateGroup )
3782 DPSP_CREATEGROUPDATA data;
3784 TRACE( "Calling SP CreateGroup\n" );
3786 data.idGroup = *lpidGroup;
3787 data.dwFlags = dwFlags;
3788 data.lpSPMessageHeader = lpMsgHdr;
3789 data.lpISP = This->dp2->spData.lpISP;
3791 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3794 /* Inform all other peers of the creation of a new group. If there are
3795 * no peers keep this quiet.
3797 if( This->dp2->lpSessionDesc &&
3798 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3800 DPMSG_CREATEPLAYERORGROUP msg;
3802 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3803 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3804 msg.dpId = *lpidGroup;
3805 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3806 msg.lpData = lpData;
3807 msg.dwDataSize = dwDataSize;
3808 msg.dpnName = *lpGroupName;
3810 /* FIXME: Correct to just use send effectively? */
3811 /* FIXME: Should size include data w/ message or just message "header" */
3812 /* FIXME: Check return code */
3813 DP_SendEx( (IDirectPlay2Impl*)This,
3814 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3815 0, 0, NULL, NULL, bAnsi );
3818 return DP_OK;
3821 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3822 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3823 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3824 DWORD dwFlags )
3826 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3828 if( This->dp2->connectionInitialized == NO_PROVIDER )
3830 return DPERR_UNINITIALIZED;
3833 if( lpidGroup == NULL ||
3834 !This->dp2->bConnectionOpen ||
3835 dwDataSize >= MAXDWORD ||
3836 ( lpData == NULL && dwDataSize != 0 ) )
3838 return DPERR_INVALIDPARAMS;
3841 *lpidGroup = DPID_UNKNOWN;
3843 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3844 lpGroupName, lpData, dwDataSize, dwFlags,
3845 TRUE );
3848 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3849 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3850 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3851 DWORD dwFlags )
3853 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3855 if( This->dp2->connectionInitialized == NO_PROVIDER )
3857 return DPERR_UNINITIALIZED;
3860 if( lpidGroup == NULL ||
3861 !This->dp2->bConnectionOpen ||
3862 dwDataSize >= MAXDWORD ||
3863 ( lpData == NULL && dwDataSize != 0 ) )
3865 return DPERR_INVALIDPARAMS;
3868 *lpidGroup = DPID_UNKNOWN;
3870 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3871 lpGroupName, lpData, dwDataSize,
3872 dwFlags, FALSE );
3875 static HRESULT DP_IF_DeleteGroupFromGroup
3876 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3878 lpGroupList lpGList;
3879 lpGroupData lpGParentData;
3881 TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3883 /* Is the parent group valid? */
3884 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3886 return DPERR_INVALIDGROUP;
3889 /* Remove the group from the parent group queue */
3890 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3892 if( lpGList == NULL )
3894 return DPERR_INVALIDGROUP;
3897 /* Decrement the ref count */
3898 lpGList->lpGData->uRef--;
3900 /* Free up the list item */
3901 HeapFree( GetProcessHeap(), 0, lpGList );
3903 /* Should send a DELETEGROUPFROMGROUP message */
3904 FIXME( "message not sent\n" );
3906 return DP_OK;
3909 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3910 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3912 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3913 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3916 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3917 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3919 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3920 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3922 static BOOL DP_BuildCompoundAddr( GUID guidDataType,
3923 LPGUID lpcSpGuid,
3924 LPVOID* lplpAddrBuf,
3925 LPDWORD lpdwBufSize )
3927 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3928 HRESULT hr;
3930 dpCompoundAddress.dwDataSize = sizeof( GUID );
3931 dpCompoundAddress.guidDataType = guidDataType;
3932 dpCompoundAddress.lpData = lpcSpGuid;
3934 *lplpAddrBuf = NULL;
3935 *lpdwBufSize = 0;
3937 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3938 lpdwBufSize, TRUE );
3940 if( hr != DPERR_BUFFERTOOSMALL )
3942 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3943 return FALSE;
3946 /* Now allocate the buffer */
3947 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3948 *lpdwBufSize );
3950 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3951 lpdwBufSize, TRUE );
3952 if( FAILED(hr) )
3954 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3955 return FALSE;
3958 return TRUE;
3961 static HRESULT WINAPI DP_IF_EnumConnections
3962 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication,
3963 LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext,
3964 DWORD dwFlags, BOOL bAnsi )
3966 HKEY hkResult;
3967 WCHAR searchSubKeySP[] = {
3968 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
3969 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
3970 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
3971 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
3972 WCHAR searchSubKeyLP[] = {
3973 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
3974 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
3975 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
3976 'L', 'o', 'b', 'b', 'y', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
3977 WCHAR guidDataSubKey[] = { 'G', 'u', 'i', 'd', 0 };
3978 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
3979 DWORD dwIndex, sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
3980 FILETIME filetime;
3982 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3983 if( dwFlags == 0 )
3985 dwFlags = DPCONNECTION_DIRECTPLAY;
3988 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3989 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) ) )
3991 return DPERR_INVALIDFLAGS;
3994 if( !lpEnumCallback )
3996 return DPERR_INVALIDPARAMS;
4000 /* Need to loop over the service providers in the registry */
4001 if( RegOpenKeyExW( HKEY_LOCAL_MACHINE,
4002 ( dwFlags & DPCONNECTION_DIRECTPLAY ) ? searchSubKeySP
4003 : searchSubKeyLP,
4004 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4006 /* Hmmm. Does this mean that there are no service providers? */
4007 ERR(": no service providers?\n");
4008 return DP_OK;
4012 /* Traverse all the service providers we have available */
4013 for( dwIndex=0;
4014 RegEnumKeyExW( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4015 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4016 ++dwIndex, sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR) )
4018 HKEY hkServiceProvider;
4019 GUID serviceProviderGUID;
4020 WCHAR guidKeyContent[39];
4021 DWORD sizeOfReturnBuffer = sizeof(guidKeyContent);
4022 DPNAME dpName;
4023 BOOL continueEnumeration = TRUE;
4025 LPVOID lpAddressBuffer = NULL;
4026 DWORD dwAddressBufferSize = 0;
4029 TRACE(" this time through: %s\n", debugstr_w(subKeyName) );
4031 /* Get a handle for this particular service provider */
4032 if( RegOpenKeyExW( hkResult, subKeyName, 0, KEY_READ,
4033 &hkServiceProvider ) != ERROR_SUCCESS )
4035 ERR(": what the heck is going on?\n" );
4036 continue;
4039 if( RegQueryValueExW( hkServiceProvider, guidDataSubKey,
4040 NULL, NULL, (LPBYTE)guidKeyContent,
4041 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4043 ERR(": missing GUID registry data members\n" );
4044 RegCloseKey(hkServiceProvider);
4045 continue;
4047 RegCloseKey(hkServiceProvider);
4049 CLSIDFromString( guidKeyContent, &serviceProviderGUID );
4051 /* Fill in the DPNAME struct for the service provider */
4052 dpName.dwSize = sizeof( dpName );
4053 dpName.dwFlags = 0;
4054 if ( bAnsi )
4056 dpName.u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4057 sizeOfSubKeyName+1 );
4058 WideCharToMultiByte( CP_ACP, 0, subKeyName,
4059 -1, dpName.u1.lpszShortNameA, -1, 0, 0);
4060 dpName.u2.lpszLongNameA = NULL;
4062 else
4064 dpName.u1.lpszShortName = subKeyName;
4065 dpName.u2.lpszLongName = NULL;
4068 /* Create the compound address for the service provider.
4069 * NOTE: This is a gruesome architectural scar right now. DP
4070 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
4071 * native dll just gets around this little bit by allocating an
4072 * 80 byte buffer which isn't even filled with a valid compound
4073 * address. Oh well. Creating a proper compound address is the
4074 * way to go anyways despite this method taking slightly more
4075 * heap space and realtime :) */
4077 if ( DP_BuildCompoundAddr( ( ( dwFlags & DPCONNECTION_DIRECTPLAY )
4078 ? DPAID_ServiceProvider
4079 : DPAID_LobbyProvider ),
4080 &serviceProviderGUID,
4081 &lpAddressBuffer,
4082 &dwAddressBufferSize ) )
4084 /* The enumeration will return FALSE if we are not to continue */
4085 continueEnumeration = lpEnumCallback( &serviceProviderGUID, lpAddressBuffer,
4086 dwAddressBufferSize, &dpName,
4087 dwFlags, lpContext );
4089 else
4091 ERR( "Couldn't build compound address\n" );
4094 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4095 if ( bAnsi )
4096 HeapFree( GetProcessHeap(), 0, dpName.u1.lpszShortNameA );
4098 if (!continueEnumeration)
4099 return DP_OK;
4102 return DP_OK;
4105 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
4106 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
4108 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4109 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
4110 return DP_IF_EnumConnections( iface, lpguidApplication, lpEnumCallback, lpContext, dwFlags, TRUE );
4113 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
4114 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
4116 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4117 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
4118 return DP_IF_EnumConnections( iface, lpguidApplication, lpEnumCallback, lpContext, dwFlags, FALSE );
4121 static HRESULT DP_IF_EnumGroupsInGroup
4122 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
4123 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
4124 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
4126 lpGroupList lpGList;
4127 lpGroupData lpGData;
4129 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
4130 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
4131 lpContext, dwFlags, bAnsi );
4133 if( This->dp2->connectionInitialized == NO_PROVIDER )
4135 return DPERR_UNINITIALIZED;
4138 if( !This->dp2->bConnectionOpen )
4140 return DPERR_NOSESSIONS;
4143 if( ( lpEnumPlayersCallback2 == NULL ) ||
4144 ( ( dwFlags & DPENUMGROUPS_SESSION ) && ( lpguidInstance == NULL ) ) )
4146 return DPERR_INVALIDPARAMS;
4149 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4151 return DPERR_INVALIDGROUP;
4154 if( DPQ_IS_EMPTY( lpGData->groups ) )
4156 return DP_OK;
4159 lpGList = DPQ_FIRST( lpGData->groups );
4161 for( ;; )
4163 /* FIXME: Should check dwFlags for match here */
4165 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
4166 &lpGList->lpGData->name, dwFlags,
4167 lpContext ) )
4169 return DP_OK; /* User requested break */
4172 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
4174 break;
4177 lpGList = DPQ_NEXT( lpGList->groups );
4181 return DP_OK;
4184 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
4185 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
4186 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
4187 DWORD dwFlags )
4189 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4190 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
4191 lpEnumPlayersCallback2, lpContext, dwFlags,
4192 TRUE );
4195 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
4196 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
4197 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
4198 DWORD dwFlags )
4200 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4201 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
4202 lpEnumPlayersCallback2, lpContext, dwFlags,
4203 FALSE );
4206 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
4207 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4209 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4210 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4211 return DP_OK;
4214 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
4215 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4217 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4218 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4219 return DP_OK;
4222 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
4223 REFGUID guidDataType,
4224 DWORD dwDataSize,
4225 LPCVOID lpData,
4226 LPVOID lpContext )
4228 /* Looking for the GUID of the provider to load */
4229 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
4230 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
4233 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4234 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
4236 if( dwDataSize != sizeof( GUID ) )
4238 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4241 memcpy( lpContext, lpData, dwDataSize );
4243 /* There shouldn't be more than 1 GUID/compound address */
4244 return FALSE;
4247 /* Still waiting for what we want */
4248 return TRUE;
4252 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4253 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4255 UINT i;
4256 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4257 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4258 LPCSTR guidDataSubKey = "Guid";
4259 LPCSTR majVerDataSubKey = "dwReserved1";
4260 LPCSTR minVerDataSubKey = "dwReserved2";
4261 LPCSTR pathSubKey = "Path";
4263 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4265 /* FIXME: Cloned code with a quick hack. */
4266 for( i=0; i<2; i++ )
4268 HKEY hkResult;
4269 LPCSTR searchSubKey;
4270 char subKeyName[51];
4271 DWORD dwIndex, sizeOfSubKeyName=50;
4272 FILETIME filetime;
4274 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4275 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4278 /* Need to loop over the service providers in the registry */
4279 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4280 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4282 /* Hmmm. Does this mean that there are no service providers? */
4283 ERR(": no service providers?\n");
4284 return 0;
4287 /* Traverse all the service providers we have available */
4288 for( dwIndex=0;
4289 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4290 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4291 ++dwIndex, sizeOfSubKeyName=51 )
4294 HKEY hkServiceProvider;
4295 GUID serviceProviderGUID;
4296 DWORD returnType, sizeOfReturnBuffer = 255;
4297 char returnBuffer[256];
4298 WCHAR buff[51];
4299 DWORD dwTemp, len;
4301 TRACE(" this time through: %s\n", subKeyName );
4303 /* Get a handle for this particular service provider */
4304 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4305 &hkServiceProvider ) != ERROR_SUCCESS )
4307 ERR(": what the heck is going on?\n" );
4308 continue;
4311 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4312 NULL, &returnType, (LPBYTE)returnBuffer,
4313 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4315 ERR(": missing GUID registry data members\n" );
4316 continue;
4319 /* FIXME: Check return types to ensure we're interpreting data right */
4320 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4321 CLSIDFromString( buff, &serviceProviderGUID );
4322 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4324 /* Determine if this is the Service Provider that the user asked for */
4325 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4327 continue;
4330 if( i == 0 ) /* DP SP */
4332 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4333 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4334 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4337 sizeOfReturnBuffer = 255;
4339 /* Get dwReserved1 */
4340 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4341 NULL, &returnType, (LPBYTE)returnBuffer,
4342 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4344 ERR(": missing dwReserved1 registry data members\n") ;
4345 continue;
4348 if( i == 0 )
4349 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4351 sizeOfReturnBuffer = 255;
4353 /* Get dwReserved2 */
4354 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4355 NULL, &returnType, (LPBYTE)returnBuffer,
4356 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4358 ERR(": missing dwReserved1 registry data members\n") ;
4359 continue;
4362 if( i == 0 )
4363 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4365 sizeOfReturnBuffer = 255;
4367 /* Get the path for this service provider */
4368 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4369 NULL, NULL, (LPBYTE)returnBuffer,
4370 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4372 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4373 continue;
4376 TRACE( "Loading %s\n", returnBuffer );
4377 return LoadLibraryA( returnBuffer );
4381 return 0;
4384 static
4385 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4387 HRESULT hr;
4388 LPDPSP_SPINIT SPInit;
4390 /* Initialize the service provider by calling SPInit */
4391 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4393 if( SPInit == NULL )
4395 ERR( "Service provider doesn't provide SPInit interface?\n" );
4396 FreeLibrary( hServiceProvider );
4397 return DPERR_UNAVAILABLE;
4400 TRACE( "Calling SPInit (DP SP entry point)\n" );
4402 hr = (*SPInit)( &This->dp2->spData );
4404 if( FAILED(hr) )
4406 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4407 FreeLibrary( hServiceProvider );
4408 return hr;
4411 /* FIXME: Need to verify the sanity of the returned callback table
4412 * using IsBadCodePtr */
4413 This->dp2->bSPInitialized = TRUE;
4415 /* This interface is now initialized as a DP object */
4416 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4418 /* Store the handle of the module so that we can unload it later */
4419 This->dp2->hServiceProvider = hServiceProvider;
4421 return hr;
4424 static
4425 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4427 HRESULT hr;
4428 LPSP_INIT DPLSPInit;
4430 /* Initialize the service provider by calling SPInit */
4431 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4433 if( DPLSPInit == NULL )
4435 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4436 FreeLibrary( hLobbyProvider );
4437 return DPERR_UNAVAILABLE;
4440 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4442 hr = (*DPLSPInit)( &This->dp2->dplspData );
4444 if( FAILED(hr) )
4446 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4447 FreeLibrary( hLobbyProvider );
4448 return hr;
4451 /* FIXME: Need to verify the sanity of the returned callback table
4452 * using IsBadCodePtr */
4454 This->dp2->bDPLSPInitialized = TRUE;
4456 /* This interface is now initialized as a lobby object */
4457 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4459 /* Store the handle of the module so that we can unload it later */
4460 This->dp2->hDPLobbyProvider = hLobbyProvider;
4462 return hr;
4465 static HRESULT DP_IF_InitializeConnection
4466 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4468 HMODULE hServiceProvider;
4469 HRESULT hr;
4470 GUID guidSP;
4471 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4472 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4474 TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4476 if ( lpConnection == NULL )
4478 return DPERR_INVALIDPARAMS;
4481 if( dwFlags != 0 )
4483 return DPERR_INVALIDFLAGS;
4486 if( This->dp2->connectionInitialized != NO_PROVIDER )
4488 return DPERR_ALREADYINITIALIZED;
4491 /* Find out what the requested SP is and how large this buffer is */
4492 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4493 dwAddrSize, &guidSP );
4495 if( FAILED(hr) )
4497 ERR( "Invalid compound address?\n" );
4498 return DPERR_UNAVAILABLE;
4501 /* Load the service provider */
4502 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4504 if( hServiceProvider == 0 )
4506 ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4507 return DPERR_UNAVAILABLE;
4510 if( bIsDpSp )
4512 /* Fill in what we can of the Service Provider required information.
4513 * The rest was be done in DP_LoadSP
4515 This->dp2->spData.lpAddress = lpConnection;
4516 This->dp2->spData.dwAddressSize = dwAddrSize;
4517 This->dp2->spData.lpGuid = &guidSP;
4519 hr = DP_InitializeDPSP( This, hServiceProvider );
4521 else
4523 This->dp2->dplspData.lpAddress = lpConnection;
4525 hr = DP_InitializeDPLSP( This, hServiceProvider );
4528 if( FAILED(hr) )
4530 return hr;
4533 return DP_OK;
4536 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4537 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4539 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4540 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4543 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4544 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4546 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4547 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4550 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4551 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4552 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4554 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4555 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4558 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4559 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4560 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4562 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4563 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4566 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4567 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4569 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4570 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4571 return DP_OK;
4574 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4575 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4577 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4578 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4579 return DP_OK;
4582 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4583 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4585 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4586 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4587 return DP_OK;
4590 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4591 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4593 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4594 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4595 return DP_OK;
4598 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4599 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4601 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4602 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4603 return DP_OK;
4606 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4607 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4609 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4610 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4611 return DP_OK;
4614 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4615 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4617 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4618 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4619 return DP_OK;
4622 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4623 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4625 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4626 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4627 return DP_OK;
4630 static HRESULT DP_IF_GetGroupParent
4631 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4632 BOOL bAnsi )
4634 lpGroupData lpGData;
4636 TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4638 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4640 return DPERR_INVALIDGROUP;
4643 *lpidGroup = lpGData->dpid;
4645 return DP_OK;
4648 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4649 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4651 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4652 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4654 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4655 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4657 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4658 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4661 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4662 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4664 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4665 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4666 return DP_OK;
4669 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4670 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4672 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4673 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4674 return DP_OK;
4677 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4678 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4680 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4681 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4682 return DP_OK;
4685 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4686 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4688 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4689 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4690 return DP_OK;
4693 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4694 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4696 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4697 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4698 return DP_OK;
4701 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4702 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4704 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4705 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4706 return DP_OK;
4709 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4710 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4712 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4713 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4714 return DP_OK;
4717 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4718 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4720 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4721 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4722 return DP_OK;
4725 static HRESULT DP_SendEx
4726 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4727 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4728 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4730 BOOL bValidDestination = FALSE;
4732 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4733 ": stub\n",
4734 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4735 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4737 if( This->dp2->connectionInitialized == NO_PROVIDER )
4739 return DPERR_UNINITIALIZED;
4742 /* FIXME: Add parameter checking */
4743 /* FIXME: First call to this needs to acquire a message id which will be
4744 * used for multiple sends
4747 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4749 /* Verify that the message is being sent from a valid local player. The
4750 * from player may be anonymous DPID_UNKNOWN
4752 if( idFrom != DPID_UNKNOWN )
4754 if( DP_FindPlayer( This, idFrom ) == NULL )
4756 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4757 return DPERR_INVALIDPLAYER;
4761 /* Verify that the message is being sent to a valid player, group or to
4762 * everyone. If it's valid, send it to those players.
4764 if( idTo == DPID_ALLPLAYERS )
4766 bValidDestination = TRUE;
4768 /* See if SP has the ability to multicast. If so, use it */
4769 if( This->dp2->spData.lpCB->SendToGroupEx )
4771 FIXME( "Use group sendex to group 0\n" );
4773 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4775 FIXME( "Use obsolete group send to group 0\n" );
4777 else /* No multicast, multiplicate */
4779 /* Send to all players we know about */
4780 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4784 if( ( !bValidDestination ) &&
4785 ( DP_FindPlayer( This, idTo ) != NULL )
4788 bValidDestination = TRUE;
4790 /* Have the service provider send this message */
4791 /* FIXME: Could optimize for local interface sends */
4792 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4793 dwTimeout, lpContext, lpdwMsgID );
4796 if( ( !bValidDestination ) &&
4797 ( DP_FindAnyGroup( This, idTo ) != NULL )
4800 bValidDestination = TRUE;
4802 /* See if SP has the ability to multicast. If so, use it */
4803 if( This->dp2->spData.lpCB->SendToGroupEx )
4805 FIXME( "Use group sendex\n" );
4807 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4809 FIXME( "Use obsolete group send to group\n" );
4811 else /* No multicast, multiplicate */
4813 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4816 #if 0
4817 if( bExpectReply )
4819 DWORD dwWaitReturn;
4821 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4823 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4824 if( dwWaitReturn != WAIT_OBJECT_0 )
4826 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4829 #endif
4832 if( !bValidDestination )
4834 return DPERR_INVALIDPLAYER;
4836 else
4838 /* FIXME: Should return what the send returned */
4839 return DP_OK;
4844 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4845 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4846 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4847 LPVOID lpContext, LPDWORD lpdwMsgID )
4849 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4850 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4851 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4854 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4855 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4856 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4857 LPVOID lpContext, LPDWORD lpdwMsgID )
4859 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4860 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4861 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4864 static HRESULT DP_SP_SendEx
4865 ( IDirectPlay2Impl* This, DWORD dwFlags,
4866 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4867 LPVOID lpContext, LPDWORD lpdwMsgID )
4869 LPDPMSG lpMElem;
4871 FIXME( ": stub\n" );
4873 /* FIXME: This queuing should only be for async messages */
4875 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4876 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4878 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4880 /* FIXME: Need to queue based on priority */
4881 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4883 return DP_OK;
4886 static HRESULT DP_IF_GetMessageQueue
4887 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4888 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4890 HRESULT hr = DP_OK;
4892 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4893 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4895 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4896 /* FIXME: What about sends which are not immediate? */
4898 if( This->dp2->spData.lpCB->GetMessageQueue )
4900 DPSP_GETMESSAGEQUEUEDATA data;
4902 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4904 /* FIXME: None of this is documented :( */
4906 data.lpISP = This->dp2->spData.lpISP;
4907 data.dwFlags = dwFlags;
4908 data.idFrom = idFrom;
4909 data.idTo = idTo;
4910 data.lpdwNumMsgs = lpdwNumMsgs;
4911 data.lpdwNumBytes = lpdwNumBytes;
4913 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4915 else
4917 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4920 return hr;
4923 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4924 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4925 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4927 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4928 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4929 lpdwNumBytes, TRUE );
4932 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4933 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4934 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4936 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4937 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4938 lpdwNumBytes, FALSE );
4941 static HRESULT DP_IF_CancelMessage
4942 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4943 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4945 HRESULT hr = DP_OK;
4947 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4948 This, dwMsgID, dwFlags, bAnsi );
4950 if( This->dp2->spData.lpCB->Cancel )
4952 DPSP_CANCELDATA data;
4954 TRACE( "Calling SP Cancel\n" );
4956 /* FIXME: Undocumented callback */
4958 data.lpISP = This->dp2->spData.lpISP;
4959 data.dwFlags = dwFlags;
4960 data.lprglpvSPMsgID = NULL;
4961 data.cSPMsgID = dwMsgID;
4962 data.dwMinPriority = dwMinPriority;
4963 data.dwMaxPriority = dwMaxPriority;
4965 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4967 else
4969 FIXME( "SP doesn't implement Cancel\n" );
4972 return hr;
4975 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4976 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4978 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4980 if( dwFlags != 0 )
4982 return DPERR_INVALIDFLAGS;
4985 if( dwMsgID == 0 )
4987 dwFlags |= DPCANCELSEND_ALL;
4990 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4993 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4994 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4996 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4998 if( dwFlags != 0 )
5000 return DPERR_INVALIDFLAGS;
5003 if( dwMsgID == 0 )
5005 dwFlags |= DPCANCELSEND_ALL;
5008 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
5011 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
5012 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
5013 DWORD dwFlags )
5015 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
5017 if( dwFlags != 0 )
5019 return DPERR_INVALIDFLAGS;
5022 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
5023 dwMaxPriority, TRUE );
5026 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
5027 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
5028 DWORD dwFlags )
5030 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
5032 if( dwFlags != 0 )
5034 return DPERR_INVALIDFLAGS;
5037 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
5038 dwMaxPriority, FALSE );
5041 /* Note: Hack so we can reuse the old functions without compiler warnings */
5042 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5043 # define XCAST(fun) (typeof(directPlay2WVT.fun))
5044 #else
5045 # define XCAST(fun) (void*)
5046 #endif
5048 static const IDirectPlay2Vtbl directPlay2WVT =
5050 XCAST(QueryInterface)DP_QueryInterface,
5051 XCAST(AddRef)DP_AddRef,
5052 XCAST(Release)DP_Release,
5054 DirectPlay2WImpl_AddPlayerToGroup,
5055 DirectPlay2WImpl_Close,
5056 DirectPlay2WImpl_CreateGroup,
5057 DirectPlay2WImpl_CreatePlayer,
5058 DirectPlay2WImpl_DeletePlayerFromGroup,
5059 DirectPlay2WImpl_DestroyGroup,
5060 DirectPlay2WImpl_DestroyPlayer,
5061 DirectPlay2WImpl_EnumGroupPlayers,
5062 DirectPlay2WImpl_EnumGroups,
5063 DirectPlay2WImpl_EnumPlayers,
5064 DirectPlay2WImpl_EnumSessions,
5065 DirectPlay2WImpl_GetCaps,
5066 DirectPlay2WImpl_GetGroupData,
5067 DirectPlay2WImpl_GetGroupName,
5068 DirectPlay2WImpl_GetMessageCount,
5069 DirectPlay2WImpl_GetPlayerAddress,
5070 DirectPlay2WImpl_GetPlayerCaps,
5071 DirectPlay2WImpl_GetPlayerData,
5072 DirectPlay2WImpl_GetPlayerName,
5073 DirectPlay2WImpl_GetSessionDesc,
5074 DirectPlay2WImpl_Initialize,
5075 DirectPlay2WImpl_Open,
5076 DirectPlay2WImpl_Receive,
5077 DirectPlay2WImpl_Send,
5078 DirectPlay2WImpl_SetGroupData,
5079 DirectPlay2WImpl_SetGroupName,
5080 DirectPlay2WImpl_SetPlayerData,
5081 DirectPlay2WImpl_SetPlayerName,
5082 DirectPlay2WImpl_SetSessionDesc
5084 #undef XCAST
5086 /* Note: Hack so we can reuse the old functions without compiler warnings */
5087 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5088 # define XCAST(fun) (typeof(directPlay2AVT.fun))
5089 #else
5090 # define XCAST(fun) (void*)
5091 #endif
5093 static const IDirectPlay2Vtbl directPlay2AVT =
5095 XCAST(QueryInterface)DP_QueryInterface,
5096 XCAST(AddRef)DP_AddRef,
5097 XCAST(Release)DP_Release,
5099 DirectPlay2AImpl_AddPlayerToGroup,
5100 DirectPlay2AImpl_Close,
5101 DirectPlay2AImpl_CreateGroup,
5102 DirectPlay2AImpl_CreatePlayer,
5103 DirectPlay2AImpl_DeletePlayerFromGroup,
5104 DirectPlay2AImpl_DestroyGroup,
5105 DirectPlay2AImpl_DestroyPlayer,
5106 DirectPlay2AImpl_EnumGroupPlayers,
5107 DirectPlay2AImpl_EnumGroups,
5108 DirectPlay2AImpl_EnumPlayers,
5109 DirectPlay2AImpl_EnumSessions,
5110 DirectPlay2AImpl_GetCaps,
5111 DirectPlay2AImpl_GetGroupData,
5112 DirectPlay2AImpl_GetGroupName,
5113 DirectPlay2AImpl_GetMessageCount,
5114 DirectPlay2AImpl_GetPlayerAddress,
5115 DirectPlay2AImpl_GetPlayerCaps,
5116 DirectPlay2AImpl_GetPlayerData,
5117 DirectPlay2AImpl_GetPlayerName,
5118 DirectPlay2AImpl_GetSessionDesc,
5119 DirectPlay2AImpl_Initialize,
5120 DirectPlay2AImpl_Open,
5121 DirectPlay2AImpl_Receive,
5122 DirectPlay2AImpl_Send,
5123 DirectPlay2AImpl_SetGroupData,
5124 DirectPlay2AImpl_SetGroupName,
5125 DirectPlay2AImpl_SetPlayerData,
5126 DirectPlay2AImpl_SetPlayerName,
5127 DirectPlay2AImpl_SetSessionDesc
5129 #undef XCAST
5132 /* Note: Hack so we can reuse the old functions without compiler warnings */
5133 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5134 # define XCAST(fun) (typeof(directPlay3AVT.fun))
5135 #else
5136 # define XCAST(fun) (void*)
5137 #endif
5139 static const IDirectPlay3Vtbl directPlay3AVT =
5141 XCAST(QueryInterface)DP_QueryInterface,
5142 XCAST(AddRef)DP_AddRef,
5143 XCAST(Release)DP_Release,
5145 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5146 XCAST(Close)DirectPlay2AImpl_Close,
5147 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5148 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5149 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5150 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5151 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5152 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5153 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5154 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5155 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5156 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5157 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5158 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5159 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5160 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5161 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5162 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5163 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5164 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5165 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5166 XCAST(Open)DirectPlay2AImpl_Open,
5167 XCAST(Receive)DirectPlay2AImpl_Receive,
5168 XCAST(Send)DirectPlay2AImpl_Send,
5169 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5170 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5171 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5172 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5173 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5175 DirectPlay3AImpl_AddGroupToGroup,
5176 DirectPlay3AImpl_CreateGroupInGroup,
5177 DirectPlay3AImpl_DeleteGroupFromGroup,
5178 DirectPlay3AImpl_EnumConnections,
5179 DirectPlay3AImpl_EnumGroupsInGroup,
5180 DirectPlay3AImpl_GetGroupConnectionSettings,
5181 DirectPlay3AImpl_InitializeConnection,
5182 DirectPlay3AImpl_SecureOpen,
5183 DirectPlay3AImpl_SendChatMessage,
5184 DirectPlay3AImpl_SetGroupConnectionSettings,
5185 DirectPlay3AImpl_StartSession,
5186 DirectPlay3AImpl_GetGroupFlags,
5187 DirectPlay3AImpl_GetGroupParent,
5188 DirectPlay3AImpl_GetPlayerAccount,
5189 DirectPlay3AImpl_GetPlayerFlags
5191 #undef XCAST
5193 /* Note: Hack so we can reuse the old functions without compiler warnings */
5194 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5195 # define XCAST(fun) (typeof(directPlay3WVT.fun))
5196 #else
5197 # define XCAST(fun) (void*)
5198 #endif
5199 static const IDirectPlay3Vtbl directPlay3WVT =
5201 XCAST(QueryInterface)DP_QueryInterface,
5202 XCAST(AddRef)DP_AddRef,
5203 XCAST(Release)DP_Release,
5205 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5206 XCAST(Close)DirectPlay2WImpl_Close,
5207 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5208 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5209 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5210 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5211 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5212 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5213 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5214 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5215 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5216 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5217 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5218 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5219 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5220 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5221 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5222 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5223 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5224 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5225 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5226 XCAST(Open)DirectPlay2WImpl_Open,
5227 XCAST(Receive)DirectPlay2WImpl_Receive,
5228 XCAST(Send)DirectPlay2WImpl_Send,
5229 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5230 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5231 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5232 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5233 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5235 DirectPlay3WImpl_AddGroupToGroup,
5236 DirectPlay3WImpl_CreateGroupInGroup,
5237 DirectPlay3WImpl_DeleteGroupFromGroup,
5238 DirectPlay3WImpl_EnumConnections,
5239 DirectPlay3WImpl_EnumGroupsInGroup,
5240 DirectPlay3WImpl_GetGroupConnectionSettings,
5241 DirectPlay3WImpl_InitializeConnection,
5242 DirectPlay3WImpl_SecureOpen,
5243 DirectPlay3WImpl_SendChatMessage,
5244 DirectPlay3WImpl_SetGroupConnectionSettings,
5245 DirectPlay3WImpl_StartSession,
5246 DirectPlay3WImpl_GetGroupFlags,
5247 DirectPlay3WImpl_GetGroupParent,
5248 DirectPlay3WImpl_GetPlayerAccount,
5249 DirectPlay3WImpl_GetPlayerFlags
5251 #undef XCAST
5253 /* Note: Hack so we can reuse the old functions without compiler warnings */
5254 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5255 # define XCAST(fun) (typeof(directPlay4WVT.fun))
5256 #else
5257 # define XCAST(fun) (void*)
5258 #endif
5259 static const IDirectPlay4Vtbl directPlay4WVT =
5261 XCAST(QueryInterface)DP_QueryInterface,
5262 XCAST(AddRef)DP_AddRef,
5263 XCAST(Release)DP_Release,
5265 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5266 XCAST(Close)DirectPlay2WImpl_Close,
5267 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5268 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5269 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5270 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5271 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5272 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5273 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5274 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5275 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5276 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5277 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5278 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5279 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5280 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5281 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5282 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5283 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5284 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5285 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5286 XCAST(Open)DirectPlay2WImpl_Open,
5287 XCAST(Receive)DirectPlay2WImpl_Receive,
5288 XCAST(Send)DirectPlay2WImpl_Send,
5289 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5290 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5291 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5292 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5293 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5295 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5296 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5297 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5298 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5299 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5300 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5301 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5302 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5303 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5304 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5305 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5306 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5307 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5308 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5309 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5311 DirectPlay4WImpl_GetGroupOwner,
5312 DirectPlay4WImpl_SetGroupOwner,
5313 DirectPlay4WImpl_SendEx,
5314 DirectPlay4WImpl_GetMessageQueue,
5315 DirectPlay4WImpl_CancelMessage,
5316 DirectPlay4WImpl_CancelPriority
5318 #undef XCAST
5321 /* Note: Hack so we can reuse the old functions without compiler warnings */
5322 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5323 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5324 #else
5325 # define XCAST(fun) (void*)
5326 #endif
5327 static const IDirectPlay4Vtbl directPlay4AVT =
5329 XCAST(QueryInterface)DP_QueryInterface,
5330 XCAST(AddRef)DP_AddRef,
5331 XCAST(Release)DP_Release,
5333 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5334 XCAST(Close)DirectPlay2AImpl_Close,
5335 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5336 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5337 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5338 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5339 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5340 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5341 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5342 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5343 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5344 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5345 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5346 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5347 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5348 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5349 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5350 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5351 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5352 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5353 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5354 XCAST(Open)DirectPlay2AImpl_Open,
5355 XCAST(Receive)DirectPlay2AImpl_Receive,
5356 XCAST(Send)DirectPlay2AImpl_Send,
5357 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5358 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5359 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5360 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5361 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5363 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5364 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5365 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5366 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5367 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5368 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5369 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5370 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5371 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5372 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5373 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5374 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5375 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5376 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5377 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5379 DirectPlay4AImpl_GetGroupOwner,
5380 DirectPlay4AImpl_SetGroupOwner,
5381 DirectPlay4AImpl_SendEx,
5382 DirectPlay4AImpl_GetMessageQueue,
5383 DirectPlay4AImpl_CancelMessage,
5384 DirectPlay4AImpl_CancelPriority
5386 #undef XCAST
5388 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5389 DPID idPlayer,
5390 LPVOID* lplpData )
5392 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5394 if( lpPlayer == NULL )
5396 return DPERR_INVALIDPLAYER;
5399 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5401 return DP_OK;
5404 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5405 DPID idPlayer,
5406 LPVOID lpData )
5408 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5410 if( lpPlayer == NULL )
5412 return DPERR_INVALIDPLAYER;
5415 lpPlayer->lpPData->lpSPPlayerData = lpData;
5417 return DP_OK;
5420 /***************************************************************************
5421 * DirectPlayEnumerateAW
5423 * The pointer to the structure lpContext will be filled with the
5424 * appropriate data for each service offered by the OS. These services are
5425 * not necessarily available on this particular machine but are defined
5426 * as simple service providers under the "Service Providers" registry key.
5427 * This structure is then passed to lpEnumCallback for each of the different
5428 * services.
5430 * This API is useful only for applications written using DirectX3 or
5431 * worse. It is superseded by IDirectPlay3::EnumConnections which also
5432 * gives information on the actual connections.
5434 * defn of a service provider:
5435 * A dynamic-link library used by DirectPlay to communicate over a network.
5436 * The service provider contains all the network-specific code required
5437 * to send and receive messages. Online services and network operators can
5438 * supply service providers to use specialized hardware, protocols, communications
5439 * media, and network resources.
5442 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5443 LPDPENUMDPCALLBACKW lpEnumCallbackW,
5444 LPVOID lpContext)
5446 HKEY hkResult;
5447 static const WCHAR searchSubKey[] = {
5448 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5449 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5450 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5451 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5452 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5453 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5455 DWORD dwIndex;
5456 FILETIME filetime;
5458 char *descriptionA = NULL;
5459 DWORD max_sizeOfDescriptionA = 0;
5460 WCHAR *descriptionW = NULL;
5461 DWORD max_sizeOfDescriptionW = 0;
5463 if (!lpEnumCallbackA && !lpEnumCallbackW)
5465 return DPERR_INVALIDPARAMS;
5468 /* Need to loop over the service providers in the registry */
5469 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5470 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5472 /* Hmmm. Does this mean that there are no service providers? */
5473 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5474 return DPERR_GENERIC;
5477 /* Traverse all the service providers we have available */
5478 dwIndex = 0;
5479 while (1)
5481 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5482 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5483 HKEY hkServiceProvider;
5484 GUID serviceProviderGUID;
5485 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5486 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5487 LONG ret_value;
5489 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5490 NULL, NULL, NULL, &filetime);
5491 if (ret_value == ERROR_NO_MORE_ITEMS)
5492 break;
5493 else if (ret_value != ERROR_SUCCESS)
5495 ERR(": could not enumerate on service provider key.\n");
5496 return DPERR_EXCEPTION;
5498 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5500 /* Open the key for this service provider */
5501 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5503 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5504 continue;
5507 /* Get the GUID from the registry */
5508 if (RegQueryValueExW(hkServiceProvider, guidKey,
5509 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5511 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5512 continue;
5514 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5516 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5517 continue;
5519 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5521 /* The enumeration will return FALSE if we are not to continue.
5523 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5524 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5525 * I think that it simply means that they are in-line with DirectX 6.0
5527 if (lpEnumCallbackA)
5529 DWORD sizeOfDescription = 0;
5531 /* Note that this is the A case of this function, so use the A variant to get the description string */
5532 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5533 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5535 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5536 continue;
5538 if (sizeOfDescription > max_sizeOfDescriptionA)
5540 HeapFree(GetProcessHeap(), 0, descriptionA);
5541 max_sizeOfDescriptionA = sizeOfDescription;
5543 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5544 RegQueryValueExA(hkServiceProvider, "DescriptionA",
5545 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5547 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5548 goto end;
5550 else
5552 DWORD sizeOfDescription = 0;
5554 if (RegQueryValueExW(hkServiceProvider, descW,
5555 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5557 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5558 continue;
5560 if (sizeOfDescription > max_sizeOfDescriptionW)
5562 HeapFree(GetProcessHeap(), 0, descriptionW);
5563 max_sizeOfDescriptionW = sizeOfDescription;
5565 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5566 RegQueryValueExW(hkServiceProvider, descW,
5567 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5569 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5570 goto end;
5573 dwIndex++;
5576 end:
5577 HeapFree(GetProcessHeap(), 0, descriptionA);
5578 HeapFree(GetProcessHeap(), 0, descriptionW);
5580 return DP_OK;
5583 /***************************************************************************
5584 * DirectPlayEnumerate [DPLAYX.9]
5585 * DirectPlayEnumerateA [DPLAYX.2]
5587 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5589 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5591 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5594 /***************************************************************************
5595 * DirectPlayEnumerateW [DPLAYX.3]
5597 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5599 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5601 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5604 typedef struct tagCreateEnum
5606 LPVOID lpConn;
5607 LPCGUID lpGuid;
5608 } CreateEnumData, *lpCreateEnumData;
5610 /* Find and copy the matching connection for the SP guid */
5611 static BOOL CALLBACK cbDPCreateEnumConnections(
5612 LPCGUID lpguidSP,
5613 LPVOID lpConnection,
5614 DWORD dwConnectionSize,
5615 LPCDPNAME lpName,
5616 DWORD dwFlags,
5617 LPVOID lpContext)
5619 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5621 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5623 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5625 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5626 dwConnectionSize );
5627 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5629 /* Found the record that we were looking for */
5630 return FALSE;
5633 /* Haven't found what were looking for yet */
5634 return TRUE;
5638 /***************************************************************************
5639 * DirectPlayCreate [DPLAYX.1]
5642 HRESULT WINAPI DirectPlayCreate
5643 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5645 HRESULT hr;
5646 LPDIRECTPLAY3A lpDP3A;
5647 CreateEnumData cbData;
5649 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5651 if( pUnk != NULL )
5653 return CLASS_E_NOAGGREGATION;
5656 if( (lplpDP == NULL) || (lpGUID == NULL) )
5658 return DPERR_INVALIDPARAMS;
5662 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5663 give them an IDirectPlay2A object and hope that doesn't cause problems */
5664 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5666 return DPERR_UNAVAILABLE;
5669 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5671 /* The GUID_NULL means don't bind a service provider. Just return the
5672 interface as is */
5673 return DP_OK;
5676 /* Bind the desired service provider since lpGUID is non NULL */
5677 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5679 /* We're going to use a DP3 interface */
5680 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5681 (LPVOID*)&lpDP3A );
5682 if( FAILED(hr) )
5684 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5685 return hr;
5688 cbData.lpConn = NULL;
5689 cbData.lpGuid = lpGUID;
5691 /* We were given a service provider, find info about it... */
5692 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5693 &cbData, DPCONNECTION_DIRECTPLAY );
5694 if( ( FAILED(hr) ) ||
5695 ( cbData.lpConn == NULL )
5698 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5699 IDirectPlayX_Release( lpDP3A );
5700 return DPERR_UNAVAILABLE;
5703 /* Initialize the service provider */
5704 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5705 if( FAILED(hr) )
5707 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5708 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5709 IDirectPlayX_Release( lpDP3A );
5710 return hr;
5713 /* Release our version of the interface now that we're done with it */
5714 IDirectPlayX_Release( lpDP3A );
5715 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5717 return DP_OK;