oleacc: Build language resource files separately.
[wine/multimedia.git] / dlls / dplayx / dplay.c
blob0c33bb35ab515e2cb843c2f78e393262c83ad8e0
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 lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
54 static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
55 LPDPNAME lpName, DWORD dwFlags,
56 HANDLE hEvent, BOOL bAnsi );
57 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
58 static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
59 LPVOID lpData, DWORD dwDataSize );
61 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, const DPID *lpid,
62 const DPNAME *lpName, DWORD dwFlags,
63 DPID idParent, BOOL bAnsi );
64 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
65 LPVOID lpData, DWORD dwDataSize );
66 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
67 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
68 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
69 DWORD dwPlayerType,
70 LPCDPNAME lpName,
71 DWORD dwFlags,
72 LPVOID lpContext );
73 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
74 static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
75 LPCDPNAME lpName, DWORD dwFlags,
76 LPVOID lpContext );
77 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
79 /* Forward declarations of virtual tables */
80 static const IDirectPlay2Vtbl directPlay2AVT;
81 static const IDirectPlay3Vtbl directPlay3AVT;
82 static const IDirectPlay4Vtbl directPlay4AVT;
84 static const IDirectPlay2Vtbl directPlay2WVT;
85 static const IDirectPlay3Vtbl directPlay3WVT;
86 static const IDirectPlay4Vtbl directPlay4WVT;
88 /* Helper methods for player/group interfaces */
89 static HRESULT DP_IF_DeletePlayerFromGroup
90 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
91 DPID idPlayer, BOOL bAnsi );
92 static HRESULT DP_IF_CreatePlayer
93 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
94 LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
95 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
96 static HRESULT DP_IF_DestroyGroup
97 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
98 static HRESULT DP_IF_DestroyPlayer
99 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
100 static HRESULT DP_IF_EnumGroupPlayers
101 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
102 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
103 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
104 static HRESULT DP_IF_EnumGroups
105 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
106 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
107 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
108 static HRESULT DP_IF_EnumPlayers
109 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
110 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
111 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
112 static HRESULT DP_IF_GetGroupData
113 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
114 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
115 static HRESULT DP_IF_GetGroupName
116 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
117 LPDWORD lpdwDataSize, BOOL bAnsi );
118 static HRESULT DP_IF_GetPlayerData
119 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
120 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
121 static HRESULT DP_IF_GetPlayerName
122 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
123 LPDWORD lpdwDataSize, BOOL bAnsi );
124 static HRESULT DP_IF_SetGroupName
125 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
126 DWORD dwFlags, BOOL bAnsi );
127 static HRESULT DP_IF_SetPlayerData
128 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
129 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
130 static HRESULT DP_IF_SetPlayerName
131 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
132 DWORD dwFlags, BOOL bAnsi );
133 static HRESULT DP_IF_AddGroupToGroup
134 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
135 static HRESULT DP_IF_CreateGroup
136 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
137 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
138 DWORD dwFlags, BOOL bAnsi );
139 static HRESULT DP_IF_CreateGroupInGroup
140 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
141 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
142 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
143 static HRESULT DP_IF_AddPlayerToGroup
144 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
145 DPID idPlayer, BOOL bAnsi );
146 static HRESULT DP_IF_DeleteGroupFromGroup
147 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
148 static HRESULT DP_SetSessionDesc
149 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
150 DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
151 static HRESULT DP_SecureOpen
152 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
153 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
154 BOOL bAnsi );
155 static HRESULT DP_SendEx
156 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
157 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
158 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
159 static HRESULT DP_IF_Receive
160 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
161 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
162 static HRESULT DP_IF_GetMessageQueue
163 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
164 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
165 static HRESULT DP_SP_SendEx
166 ( IDirectPlay2Impl* This, DWORD dwFlags,
167 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
168 LPVOID lpContext, LPDWORD lpdwMsgID );
169 static HRESULT DP_IF_SetGroupData
170 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
171 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
172 static HRESULT DP_IF_GetPlayerCaps
173 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
174 DWORD dwFlags );
175 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
176 static HRESULT DP_IF_CancelMessage
177 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
178 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
179 static HRESULT DP_IF_EnumGroupsInGroup
180 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
181 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
182 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
183 static HRESULT DP_IF_GetGroupParent
184 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
185 BOOL bAnsi );
186 static HRESULT DP_IF_GetCaps
187 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
188 static HRESULT DP_IF_EnumSessions
189 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
190 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
191 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
192 static HRESULT DP_IF_InitializeConnection
193 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
194 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
195 LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
196 DWORD dwFlags, LPVOID lpContext );
197 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
198 LPDWORD lpdwBufSize );
202 static inline DPID DP_NextObjectId(void);
203 static DPID DP_GetRemoteNextObjectId(void);
205 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
206 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
207 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
210 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
211 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
212 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
219 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
220 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
221 we don't have to change much */
222 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
224 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
225 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
227 /* Strip out all dwFlags values for CREATEPLAYER msg */
228 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
230 static LONG kludgePlayerGroupId = 1000;
232 /* ------------------------------------------------------------------ */
235 static BOOL DP_CreateIUnknown( LPVOID lpDP )
237 IDirectPlay2AImpl *This = lpDP;
239 This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
240 if ( This->unk == NULL )
242 return FALSE;
245 InitializeCriticalSection( &This->unk->DP_lock );
246 This->unk->DP_lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlay2AImpl*->DirectPlayIUnknownData*->DP_lock");
248 return TRUE;
251 static BOOL DP_DestroyIUnknown( LPVOID lpDP )
253 IDirectPlay2AImpl *This = lpDP;
255 This->unk->DP_lock.DebugInfo->Spare[0] = 0;
256 DeleteCriticalSection( &This->unk->DP_lock );
257 HeapFree( GetProcessHeap(), 0, This->unk );
259 return TRUE;
262 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
264 IDirectPlay2AImpl *This = lpDP;
266 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
267 if ( This->dp2 == NULL )
269 return FALSE;
272 This->dp2->bConnectionOpen = FALSE;
274 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
275 This->dp2->dwEnumSessionLock = 0;
277 This->dp2->bHostInterface = FALSE;
279 DPQ_INIT(This->dp2->receiveMsgs);
280 DPQ_INIT(This->dp2->sendMsgs);
281 DPQ_INIT(This->dp2->replysExpected);
283 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
285 /* FIXME: Memory leak */
286 return FALSE;
289 /* Provide an initial session desc with nothing in it */
290 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
291 HEAP_ZERO_MEMORY,
292 sizeof( *This->dp2->lpSessionDesc ) );
293 if( This->dp2->lpSessionDesc == NULL )
295 /* FIXME: Memory leak */
296 return FALSE;
298 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
300 /* We are emulating a dp 6 implementation */
301 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
303 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
304 sizeof( *This->dp2->spData.lpCB ) );
305 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
306 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
308 /* This is the pointer to the service provider */
309 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
310 (LPVOID*)&This->dp2->spData.lpISP, This ) )
313 /* FIXME: Memory leak */
314 return FALSE;
317 /* Setup lobby provider information */
318 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
319 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
320 sizeof( *This->dp2->dplspData.lpCB ) );
321 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
323 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
324 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
327 /* FIXME: Memory leak */
328 return FALSE;
331 return TRUE;
334 /* Definition of the global function in dplayx_queue.h. #
335 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
336 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
338 HeapFree( GetProcessHeap(), 0, elem );
341 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
343 IDirectPlay2AImpl *This = lpDP;
345 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
347 TerminateThread( This->dp2->hEnumSessionThread, 0 );
348 CloseHandle( This->dp2->hEnumSessionThread );
351 /* Finish with the SP - have it shutdown */
352 if( This->dp2->spData.lpCB->ShutdownEx )
354 DPSP_SHUTDOWNDATA data;
356 TRACE( "Calling SP ShutdownEx\n" );
358 data.lpISP = This->dp2->spData.lpISP;
360 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
362 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
364 TRACE( "Calling obsolete SP Shutdown\n" );
365 (*This->dp2->spData.lpCB->Shutdown)();
368 /* Unload the SP (if it exists) */
369 if( This->dp2->hServiceProvider != 0 )
371 FreeLibrary( This->dp2->hServiceProvider );
374 /* Unload the Lobby Provider (if it exists) */
375 if( This->dp2->hDPLobbyProvider != 0 )
377 FreeLibrary( This->dp2->hDPLobbyProvider );
380 /* FIXME: Need to delete receive and send msgs queue contents */
382 NS_DeleteSessionCache( This->dp2->lpNameServerData );
384 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
386 IDirectPlaySP_Release( This->dp2->spData.lpISP );
388 /* Delete the contents */
389 HeapFree( GetProcessHeap(), 0, This->dp2 );
391 return TRUE;
394 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
396 IDirectPlay3AImpl *This = lpDP;
398 This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
399 if ( This->dp3 == NULL )
401 return FALSE;
404 return TRUE;
407 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
409 IDirectPlay3AImpl *This = lpDP;
411 /* Delete the contents */
412 HeapFree( GetProcessHeap(), 0, This->dp3 );
414 return TRUE;
417 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
419 IDirectPlay4AImpl *This = lpDP;
421 This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
422 if ( This->dp4 == NULL )
424 return FALSE;
427 return TRUE;
430 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
432 IDirectPlay3AImpl *This = lpDP;
434 /* Delete the contents */
435 HeapFree( GetProcessHeap(), 0, This->dp4 );
437 return TRUE;
441 /* Create a new interface */
442 HRESULT DP_CreateInterface
443 ( REFIID riid, LPVOID* ppvObj )
445 TRACE( " for %s\n", debugstr_guid( riid ) );
447 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
448 sizeof( IDirectPlay2Impl ) );
450 if( *ppvObj == NULL )
452 return DPERR_OUTOFMEMORY;
455 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
457 IDirectPlay2Impl *This = *ppvObj;
458 This->lpVtbl = &directPlay2WVT;
460 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
462 IDirectPlay2AImpl *This = *ppvObj;
463 This->lpVtbl = &directPlay2AVT;
465 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
467 IDirectPlay3Impl *This = *ppvObj;
468 This->lpVtbl = &directPlay3WVT;
470 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
472 IDirectPlay3AImpl *This = *ppvObj;
473 This->lpVtbl = &directPlay3AVT;
475 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
477 IDirectPlay4Impl *This = *ppvObj;
478 This->lpVtbl = &directPlay4WVT;
480 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
482 IDirectPlay4AImpl *This = *ppvObj;
483 This->lpVtbl = &directPlay4AVT;
485 else
487 /* Unsupported interface */
488 HeapFree( GetProcessHeap(), 0, *ppvObj );
489 *ppvObj = NULL;
491 return E_NOINTERFACE;
494 /* Initialize it */
495 if ( DP_CreateIUnknown( *ppvObj ) &&
496 DP_CreateDirectPlay2( *ppvObj ) &&
497 DP_CreateDirectPlay3( *ppvObj ) &&
498 DP_CreateDirectPlay4( *ppvObj )
501 IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
503 return S_OK;
506 /* Initialize failed, destroy it */
507 DP_DestroyDirectPlay4( *ppvObj );
508 DP_DestroyDirectPlay3( *ppvObj );
509 DP_DestroyDirectPlay2( *ppvObj );
510 DP_DestroyIUnknown( *ppvObj );
512 HeapFree( GetProcessHeap(), 0, *ppvObj );
514 *ppvObj = NULL;
515 return DPERR_NOMEMORY;
519 /* Direct Play methods */
521 /* Shared between all dplay types */
522 static HRESULT WINAPI DP_QueryInterface
523 ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
525 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
526 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
528 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
529 sizeof( *This ) );
531 if( *ppvObj == NULL )
533 return DPERR_OUTOFMEMORY;
536 CopyMemory( *ppvObj, This, sizeof( *This ) );
537 (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
539 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
541 IDirectPlay2Impl *This = *ppvObj;
542 This->lpVtbl = &directPlay2WVT;
544 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
546 IDirectPlay2AImpl *This = *ppvObj;
547 This->lpVtbl = &directPlay2AVT;
549 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
551 IDirectPlay3Impl *This = *ppvObj;
552 This->lpVtbl = &directPlay3WVT;
554 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
556 IDirectPlay3AImpl *This = *ppvObj;
557 This->lpVtbl = &directPlay3AVT;
559 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
561 IDirectPlay4Impl *This = *ppvObj;
562 This->lpVtbl = &directPlay4WVT;
564 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
566 IDirectPlay4AImpl *This = *ppvObj;
567 This->lpVtbl = &directPlay4AVT;
569 else
571 /* Unsupported interface */
572 HeapFree( GetProcessHeap(), 0, *ppvObj );
573 *ppvObj = NULL;
575 return E_NOINTERFACE;
578 IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
580 return S_OK;
583 /* Shared between all dplay types */
584 static ULONG WINAPI DP_AddRef
585 ( LPDIRECTPLAY3 iface )
587 ULONG ulInterfaceRefCount, ulObjRefCount;
588 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
590 ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
591 ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
593 TRACE( "ref count incremented to %u:%u for %p\n",
594 ulInterfaceRefCount, ulObjRefCount, This );
596 return ulObjRefCount;
599 static ULONG WINAPI DP_Release
600 ( LPDIRECTPLAY3 iface )
602 ULONG ulInterfaceRefCount, ulObjRefCount;
604 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
606 ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
607 ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
609 TRACE( "ref count decremented to %u:%u for %p\n",
610 ulInterfaceRefCount, ulObjRefCount, This );
612 /* Deallocate if this is the last reference to the object */
613 if( ulObjRefCount == 0 )
615 /* If we're destroying the object, this must be the last ref
616 of the last interface */
617 DP_DestroyDirectPlay4( This );
618 DP_DestroyDirectPlay3( This );
619 DP_DestroyDirectPlay2( This );
620 DP_DestroyIUnknown( This );
623 /* Deallocate the interface */
624 if( ulInterfaceRefCount == 0 )
626 HeapFree( GetProcessHeap(), 0, This );
629 return ulObjRefCount;
632 static inline DPID DP_NextObjectId(void)
634 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
637 /* *lplpReply will be non NULL iff there is something to reply */
638 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
639 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
640 WORD wCommandId, WORD wVersion,
641 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
643 TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
644 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
645 wVersion );
647 switch( wCommandId )
649 /* Name server needs to handle this request */
650 case DPMSGCMD_ENUMSESSIONSREQUEST:
652 /* Reply expected */
653 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
655 break;
658 /* Name server needs to handle this request */
659 case DPMSGCMD_ENUMSESSIONSREPLY:
661 /* No reply expected */
662 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
663 This->dp2->spData.dwSPHeaderSize,
664 lpcMessageBody,
665 This->dp2->lpNameServerData );
666 break;
669 case DPMSGCMD_REQUESTNEWPLAYERID:
671 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = lpcMessageBody;
673 LPDPMSG_NEWPLAYERIDREPLY lpReply;
675 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
677 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
679 FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
680 lpcMsg->dwFlags );
682 /* Setup the reply */
683 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
684 This->dp2->spData.dwSPHeaderSize );
686 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
687 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
688 lpReply->envelope.wVersion = DPMSGVER_DP6;
690 lpReply->dpidNewPlayerId = DP_NextObjectId();
692 TRACE( "Allocating new playerid 0x%08x from remote request\n",
693 lpReply->dpidNewPlayerId );
695 break;
698 case DPMSGCMD_GETNAMETABLEREPLY:
699 case DPMSGCMD_NEWPLAYERIDREPLY:
702 #if 0
703 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
704 DebugBreak();
705 #endif
706 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
708 break;
711 #if 1
712 case DPMSGCMD_JUSTENVELOPE:
714 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
715 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
716 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
718 #endif
720 case DPMSGCMD_FORWARDADDPLAYER:
722 #if 0
723 DebugBreak();
724 #endif
725 #if 1
726 TRACE( "Sending message to self to get my addr\n" );
727 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
728 #endif
729 break;
732 case DPMSGCMD_FORWARDADDPLAYERNACK:
734 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
735 break;
738 default:
740 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
741 DebugBreak();
742 break;
746 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
748 return DP_OK;
752 static HRESULT DP_IF_AddPlayerToGroup
753 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
754 DPID idPlayer, BOOL bAnsi )
756 lpGroupData lpGData;
757 lpPlayerList lpPList;
758 lpPlayerList lpNewPList;
760 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
761 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
763 if( This->dp2->connectionInitialized == NO_PROVIDER )
765 return DPERR_UNINITIALIZED;
768 /* Find the group */
769 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
771 return DPERR_INVALIDGROUP;
774 /* Find the player */
775 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
777 return DPERR_INVALIDPLAYER;
780 /* Create a player list (ie "shortcut" ) */
781 lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
782 if( lpNewPList == NULL )
784 return DPERR_CANTADDPLAYER;
787 /* Add the shortcut */
788 lpPList->lpPData->uRef++;
789 lpNewPList->lpPData = lpPList->lpPData;
791 /* Add the player to the list of players for this group */
792 DPQ_INSERT(lpGData->players,lpNewPList,players);
794 /* Let the SP know that we've added a player to the group */
795 if( This->dp2->spData.lpCB->AddPlayerToGroup )
797 DPSP_ADDPLAYERTOGROUPDATA data;
799 TRACE( "Calling SP AddPlayerToGroup\n" );
801 data.idPlayer = idPlayer;
802 data.idGroup = idGroup;
803 data.lpISP = This->dp2->spData.lpISP;
805 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
808 /* Inform all other peers of the addition of player to the group. If there are
809 * no peers keep this event quiet.
810 * Also, if this event was the result of another machine sending it to us,
811 * don't bother rebroadcasting it.
813 if( ( lpMsgHdr == NULL ) &&
814 This->dp2->lpSessionDesc &&
815 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
817 DPMSG_ADDPLAYERTOGROUP msg;
818 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
820 msg.dpIdGroup = idGroup;
821 msg.dpIdPlayer = idPlayer;
823 /* FIXME: Correct to just use send effectively? */
824 /* FIXME: Should size include data w/ message or just message "header" */
825 /* FIXME: Check return code */
826 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
829 return DP_OK;
832 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
833 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
835 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
836 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
839 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
840 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
842 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
843 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
846 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
848 HRESULT hr = DP_OK;
850 TRACE("(%p)->(%u)\n", This, bAnsi );
852 /* FIXME: Need to find a new host I assume (how?) */
853 /* FIXME: Need to destroy all local groups */
854 /* FIXME: Need to migrate all remotely visible players to the new host */
856 /* Invoke the SP callback to inform of session close */
857 if( This->dp2->spData.lpCB->CloseEx )
859 DPSP_CLOSEDATA data;
861 TRACE( "Calling SP CloseEx\n" );
863 data.lpISP = This->dp2->spData.lpISP;
865 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
868 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
870 TRACE( "Calling SP Close (obsolete interface)\n" );
872 hr = (*This->dp2->spData.lpCB->Close)();
875 return hr;
878 static HRESULT WINAPI DirectPlay2AImpl_Close
879 ( LPDIRECTPLAY2A iface )
881 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
882 return DP_IF_Close( This, TRUE );
885 static HRESULT WINAPI DirectPlay2WImpl_Close
886 ( LPDIRECTPLAY2 iface )
888 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
889 return DP_IF_Close( This, FALSE );
892 static
893 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
894 const DPNAME *lpName, DWORD dwFlags,
895 DPID idParent, BOOL bAnsi )
897 lpGroupData lpGData;
899 /* Allocate the new space and add to end of high level group list */
900 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
902 if( lpGData == NULL )
904 return NULL;
907 DPQ_INIT(lpGData->groups);
908 DPQ_INIT(lpGData->players);
910 /* Set the desired player ID - no sanity checking to see if it exists */
911 lpGData->dpid = *lpid;
913 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
915 /* FIXME: Should we check that the parent exists? */
916 lpGData->parent = idParent;
918 /* FIXME: Should we validate the dwFlags? */
919 lpGData->dwFlags = dwFlags;
921 TRACE( "Created group id 0x%08x\n", *lpid );
923 return lpGData;
926 /* This method assumes that all links to it are already deleted */
927 static void
928 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
930 lpGroupList lpGList;
932 TRACE( "(%p)->(0x%08x)\n", This, dpid );
934 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
936 if( lpGList == NULL )
938 ERR( "DPID 0x%08x not found\n", dpid );
939 return;
942 if( --(lpGList->lpGData->uRef) )
944 FIXME( "Why is this not the last reference to group?\n" );
945 DebugBreak();
948 /* Delete player */
949 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
950 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
952 /* Remove and Delete Player List object */
953 HeapFree( GetProcessHeap(), 0, lpGList );
957 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
959 lpGroupList lpGroups;
961 TRACE( "(%p)->(0x%08x)\n", This, dpid );
963 if( dpid == DPID_SYSTEM_GROUP )
965 return This->dp2->lpSysGroup;
967 else
969 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
972 if( lpGroups == NULL )
974 return NULL;
977 return lpGroups->lpGData;
980 static HRESULT DP_IF_CreateGroup
981 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
982 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
983 DWORD dwFlags, BOOL bAnsi )
985 lpGroupData lpGData;
987 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
988 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
989 dwFlags, bAnsi );
991 if( This->dp2->connectionInitialized == NO_PROVIDER )
993 return DPERR_UNINITIALIZED;
996 /* If the name is not specified, we must provide one */
997 if( DPID_UNKNOWN == *lpidGroup )
999 /* If we are the name server, we decide on the group ids. If not, we
1000 * must ask for one before attempting a creation.
1002 if( This->dp2->bHostInterface )
1004 *lpidGroup = DP_NextObjectId();
1006 else
1008 *lpidGroup = DP_GetRemoteNextObjectId();
1012 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1013 DPID_NOPARENT_GROUP, bAnsi );
1015 if( lpGData == NULL )
1017 return DPERR_CANTADDPLAYER; /* yes player not group */
1020 if( DPID_SYSTEM_GROUP == *lpidGroup )
1022 This->dp2->lpSysGroup = lpGData;
1023 TRACE( "Inserting system group\n" );
1025 else
1027 /* Insert into the system group */
1028 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1029 lpGroup->lpGData = lpGData;
1031 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1034 /* Something is now referencing this data */
1035 lpGData->uRef++;
1037 /* Set all the important stuff for the group */
1038 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1040 /* FIXME: We should only create the system group if GetCaps returns
1041 * DPCAPS_GROUPOPTIMIZED.
1044 /* Let the SP know that we've created this group */
1045 if( This->dp2->spData.lpCB->CreateGroup )
1047 DPSP_CREATEGROUPDATA data;
1048 DWORD dwCreateFlags = 0;
1050 TRACE( "Calling SP CreateGroup\n" );
1052 if( *lpidGroup == DPID_NOPARENT_GROUP )
1053 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1055 if( lpMsgHdr == NULL )
1056 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1058 if( dwFlags & DPGROUP_HIDDEN )
1059 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1061 data.idGroup = *lpidGroup;
1062 data.dwFlags = dwCreateFlags;
1063 data.lpSPMessageHeader = lpMsgHdr;
1064 data.lpISP = This->dp2->spData.lpISP;
1066 (*This->dp2->spData.lpCB->CreateGroup)( &data );
1069 /* Inform all other peers of the creation of a new group. If there are
1070 * no peers keep this event quiet.
1071 * Also if this message was sent to us, don't rebroadcast.
1073 if( ( lpMsgHdr == NULL ) &&
1074 This->dp2->lpSessionDesc &&
1075 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1077 DPMSG_CREATEPLAYERORGROUP msg;
1078 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1080 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
1081 msg.dpId = *lpidGroup;
1082 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1083 msg.lpData = lpData;
1084 msg.dwDataSize = dwDataSize;
1085 msg.dpnName = *lpGroupName;
1086 msg.dpIdParent = DPID_NOPARENT_GROUP;
1087 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1089 /* FIXME: Correct to just use send effectively? */
1090 /* FIXME: Should size include data w/ message or just message "header" */
1091 /* FIXME: Check return code */
1092 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
1093 0, 0, NULL, NULL, bAnsi );
1096 return DP_OK;
1099 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
1100 ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1101 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1103 *lpidGroup = DPID_UNKNOWN;
1105 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1106 lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
1109 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1110 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1111 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1113 *lpidGroup = DPID_UNKNOWN;
1115 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1116 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
1120 static void
1121 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1122 LPVOID lpData, DWORD dwDataSize )
1124 /* Clear out the data with this player */
1125 if( dwFlags & DPSET_LOCAL )
1127 if ( lpGData->dwLocalDataSize != 0 )
1129 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1130 lpGData->lpLocalData = NULL;
1131 lpGData->dwLocalDataSize = 0;
1134 else
1136 if( lpGData->dwRemoteDataSize != 0 )
1138 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1139 lpGData->lpRemoteData = NULL;
1140 lpGData->dwRemoteDataSize = 0;
1144 /* Reallocate for new data */
1145 if( lpData != NULL )
1147 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1148 sizeof( dwDataSize ) );
1149 CopyMemory( lpNewData, lpData, dwDataSize );
1151 if( dwFlags & DPSET_LOCAL )
1153 lpGData->lpLocalData = lpData;
1154 lpGData->dwLocalDataSize = dwDataSize;
1156 else
1158 lpGData->lpRemoteData = lpNewData;
1159 lpGData->dwRemoteDataSize = dwDataSize;
1165 /* This function will just create the storage for the new player. */
1166 static
1167 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1168 LPDPNAME lpName, DWORD dwFlags,
1169 HANDLE hEvent, BOOL bAnsi )
1171 lpPlayerData lpPData;
1173 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1175 /* Allocate the storage for the player and associate it with list element */
1176 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1177 if( lpPData == NULL )
1179 return NULL;
1182 /* Set the desired player ID */
1183 lpPData->dpid = *lpid;
1185 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1187 lpPData->dwFlags = dwFlags;
1189 /* If we were given an event handle, duplicate it */
1190 if( hEvent != 0 )
1192 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1193 GetCurrentProcess(), &lpPData->hEvent,
1194 0, FALSE, DUPLICATE_SAME_ACCESS )
1197 /* FIXME: Memory leak */
1198 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1202 /* Initialize the SP data section */
1203 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1205 TRACE( "Created player id 0x%08x\n", *lpid );
1207 if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1208 This->dp2->lpSessionDesc->dwCurrentPlayers++;
1210 return lpPData;
1213 /* Delete the contents of the DPNAME struct */
1214 static void
1215 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1217 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1218 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1221 /* This method assumes that all links to it are already deleted */
1222 static void
1223 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1225 lpPlayerList lpPList;
1227 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1229 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1231 if( lpPList == NULL )
1233 ERR( "DPID 0x%08x not found\n", dpid );
1234 return;
1237 /* Verify that this is the last reference to the data */
1238 if( --(lpPList->lpPData->uRef) )
1240 FIXME( "Why is this not the last reference to player?\n" );
1241 DebugBreak();
1244 /* Delete player */
1245 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1247 CloseHandle( lpPList->lpPData->hEvent );
1248 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1250 /* Delete Player List object */
1251 HeapFree( GetProcessHeap(), 0, lpPList );
1254 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1256 lpPlayerList lpPlayers;
1258 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1260 if(This->dp2->lpSysGroup == NULL)
1261 return NULL;
1263 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1265 return lpPlayers;
1268 /* Basic area for Dst must already be allocated */
1269 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1271 if( lpSrc == NULL )
1273 ZeroMemory( lpDst, sizeof( *lpDst ) );
1274 lpDst->dwSize = sizeof( *lpDst );
1275 return TRUE;
1278 if( lpSrc->dwSize != sizeof( *lpSrc) )
1280 return FALSE;
1283 /* Delete any existing pointers */
1284 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1285 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1287 /* Copy as required */
1288 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1290 if( bAnsi )
1292 if( lpSrc->u1.lpszShortNameA )
1294 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1295 strlen(lpSrc->u1.lpszShortNameA)+1 );
1296 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1298 if( lpSrc->u2.lpszLongNameA )
1300 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1301 strlen(lpSrc->u2.lpszLongNameA)+1 );
1302 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1305 else
1307 if( lpSrc->u1.lpszShortNameA )
1309 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1310 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1311 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1313 if( lpSrc->u2.lpszLongNameA )
1315 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1316 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1317 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1321 return TRUE;
1324 static void
1325 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1326 LPVOID lpData, DWORD dwDataSize )
1328 /* Clear out the data with this player */
1329 if( dwFlags & DPSET_LOCAL )
1331 if ( lpPData->dwLocalDataSize != 0 )
1333 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1334 lpPData->lpLocalData = NULL;
1335 lpPData->dwLocalDataSize = 0;
1338 else
1340 if( lpPData->dwRemoteDataSize != 0 )
1342 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1343 lpPData->lpRemoteData = NULL;
1344 lpPData->dwRemoteDataSize = 0;
1348 /* Reallocate for new data */
1349 if( lpData != NULL )
1351 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1352 sizeof( dwDataSize ) );
1353 CopyMemory( lpNewData, lpData, dwDataSize );
1355 if( dwFlags & DPSET_LOCAL )
1357 lpPData->lpLocalData = lpData;
1358 lpPData->dwLocalDataSize = dwDataSize;
1360 else
1362 lpPData->lpRemoteData = lpNewData;
1363 lpPData->dwRemoteDataSize = dwDataSize;
1369 static HRESULT DP_IF_CreatePlayer
1370 ( IDirectPlay2Impl* This,
1371 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1372 LPDPID lpidPlayer,
1373 LPDPNAME lpPlayerName,
1374 HANDLE hEvent,
1375 LPVOID lpData,
1376 DWORD dwDataSize,
1377 DWORD dwFlags,
1378 BOOL bAnsi )
1380 HRESULT hr = DP_OK;
1381 lpPlayerData lpPData;
1382 lpPlayerList lpPList;
1383 DWORD dwCreateFlags = 0;
1385 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1386 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1387 dwDataSize, dwFlags, bAnsi );
1388 if( This->dp2->connectionInitialized == NO_PROVIDER )
1390 return DPERR_UNINITIALIZED;
1393 if( dwFlags == 0 )
1395 dwFlags = DPPLAYER_SPECTATOR;
1398 if( lpidPlayer == NULL )
1400 return DPERR_INVALIDPARAMS;
1404 /* Determine the creation flags for the player. These will be passed
1405 * to the name server if requesting a player id and to the SP when
1406 * informing it of the player creation
1409 if( dwFlags & DPPLAYER_SERVERPLAYER )
1411 if( *lpidPlayer == DPID_SERVERPLAYER )
1413 /* Server player for the host interface */
1414 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1416 else if( *lpidPlayer == DPID_NAME_SERVER )
1418 /* Name server - master of everything */
1419 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1421 else
1423 /* Server player for a non host interface */
1424 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1428 if( lpMsgHdr == NULL )
1429 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1432 /* Verify we know how to handle all the flags */
1433 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1434 ( dwFlags & DPPLAYER_SPECTATOR )
1438 /* Assume non fatal failure */
1439 ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1442 /* If the name is not specified, we must provide one */
1443 if( *lpidPlayer == DPID_UNKNOWN )
1445 /* If we are the session master, we dish out the group/player ids */
1446 if( This->dp2->bHostInterface )
1448 *lpidPlayer = DP_NextObjectId();
1450 else
1452 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1454 if( FAILED(hr) )
1456 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1457 return hr;
1461 else
1463 /* FIXME: Would be nice to perhaps verify that we don't already have
1464 * this player.
1468 /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
1469 player total */
1470 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1471 hEvent, bAnsi );
1473 if( lpPData == NULL )
1475 return DPERR_CANTADDPLAYER;
1478 /* Create the list object and link it in */
1479 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1480 if( lpPList == NULL )
1482 FIXME( "Memory leak\n" );
1483 return DPERR_CANTADDPLAYER;
1486 lpPData->uRef = 1;
1487 lpPList->lpPData = lpPData;
1489 /* Add the player to the system group */
1490 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1492 /* Update the information and send it to all players in the session */
1493 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1495 /* Let the SP know that we've created this player */
1496 if( This->dp2->spData.lpCB->CreatePlayer )
1498 DPSP_CREATEPLAYERDATA data;
1500 data.idPlayer = *lpidPlayer;
1501 data.dwFlags = dwCreateFlags;
1502 data.lpSPMessageHeader = lpMsgHdr;
1503 data.lpISP = This->dp2->spData.lpISP;
1505 TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1506 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1508 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1511 if( FAILED(hr) )
1513 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1514 return hr;
1517 /* Now let the SP know that this player is a member of the system group */
1518 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1520 DPSP_ADDPLAYERTOGROUPDATA data;
1522 data.idPlayer = *lpidPlayer;
1523 data.idGroup = DPID_SYSTEM_GROUP;
1524 data.lpISP = This->dp2->spData.lpISP;
1526 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1528 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1531 if( FAILED(hr) )
1533 ERR( "Failed to add player to sys group with sp: %s\n",
1534 DPLAYX_HresultToString(hr) );
1535 return hr;
1538 #if 1
1539 if( This->dp2->bHostInterface == FALSE )
1541 /* Let the name server know about the creation of this player */
1542 /* FIXME: Is this only to be done for the creation of a server player or
1543 * is this used for regular players? If only for server players, move
1544 * this call to DP_SecureOpen(...);
1546 #if 0
1547 TRACE( "Sending message to self to get my addr\n" );
1548 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1549 #endif
1551 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1553 #else
1554 /* Inform all other peers of the creation of a new player. If there are
1555 * no peers keep this quiet.
1556 * Also, if this was a remote event, no need to rebroadcast it.
1558 if( ( lpMsgHdr == NULL ) &&
1559 This->dp2->lpSessionDesc &&
1560 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1562 DPMSG_CREATEPLAYERORGROUP msg;
1563 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1565 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1566 msg.dpId = *lpidPlayer;
1567 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1568 msg.lpData = lpData;
1569 msg.dwDataSize = dwDataSize;
1570 msg.dpnName = *lpPlayerName;
1571 msg.dpIdParent = DPID_NOPARENT_GROUP;
1572 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1574 /* FIXME: Correct to just use send effectively? */
1575 /* FIXME: Should size include data w/ message or just message "header" */
1576 /* FIXME: Check return code */
1577 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1578 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1580 #endif
1582 return hr;
1585 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1586 ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1587 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1589 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1591 if( lpidPlayer == NULL )
1593 return DPERR_INVALIDPARAMS;
1596 if( dwFlags & DPPLAYER_SERVERPLAYER )
1598 *lpidPlayer = DPID_SERVERPLAYER;
1600 else
1602 *lpidPlayer = DPID_UNKNOWN;
1605 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1606 lpData, dwDataSize, dwFlags, TRUE );
1609 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1610 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1611 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1613 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1615 if( lpidPlayer == NULL )
1617 return DPERR_INVALIDPARAMS;
1620 if( dwFlags & DPPLAYER_SERVERPLAYER )
1622 *lpidPlayer = DPID_SERVERPLAYER;
1624 else
1626 *lpidPlayer = DPID_UNKNOWN;
1629 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1630 lpData, dwDataSize, dwFlags, FALSE );
1633 static DPID DP_GetRemoteNextObjectId(void)
1635 FIXME( ":stub\n" );
1637 /* Hack solution */
1638 return DP_NextObjectId();
1641 static HRESULT DP_IF_DeletePlayerFromGroup
1642 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1643 DPID idPlayer, BOOL bAnsi )
1645 HRESULT hr = DP_OK;
1647 lpGroupData lpGData;
1648 lpPlayerList lpPList;
1650 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
1651 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1653 /* Find the group */
1654 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1656 return DPERR_INVALIDGROUP;
1659 /* Find the player */
1660 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1662 return DPERR_INVALIDPLAYER;
1665 /* Remove the player shortcut from the group */
1666 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1668 if( lpPList == NULL )
1670 return DPERR_INVALIDPLAYER;
1673 /* One less reference */
1674 lpPList->lpPData->uRef--;
1676 /* Delete the Player List element */
1677 HeapFree( GetProcessHeap(), 0, lpPList );
1679 /* Inform the SP if they care */
1680 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1682 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1684 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1686 data.idPlayer = idPlayer;
1687 data.idGroup = idGroup;
1688 data.lpISP = This->dp2->spData.lpISP;
1690 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1693 /* Need to send a DELETEPLAYERFROMGROUP message */
1694 FIXME( "Need to send a message\n" );
1696 return hr;
1699 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1700 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1702 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1703 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1706 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1707 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1709 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1710 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1713 typedef struct _DPRGOPContext
1715 IDirectPlay3Impl* This;
1716 BOOL bAnsi;
1717 DPID idGroup;
1718 } DPRGOPContext, *lpDPRGOPContext;
1720 static BOOL CALLBACK
1721 cbRemoveGroupOrPlayer(
1722 DPID dpId,
1723 DWORD dwPlayerType,
1724 LPCDPNAME lpName,
1725 DWORD dwFlags,
1726 LPVOID lpContext )
1728 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1730 TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1731 dpId, dwPlayerType, lpCtxt->idGroup );
1733 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1735 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1736 dpId )
1740 ERR( "Unable to delete group 0x%08x from group 0x%08x\n",
1741 dpId, lpCtxt->idGroup );
1744 else
1746 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1747 NULL, lpCtxt->idGroup,
1748 dpId, lpCtxt->bAnsi )
1752 ERR( "Unable to delete player 0x%08x from grp 0x%08x\n",
1753 dpId, lpCtxt->idGroup );
1757 return TRUE; /* Continue enumeration */
1760 static HRESULT DP_IF_DestroyGroup
1761 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1763 lpGroupData lpGData;
1764 DPRGOPContext context;
1766 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1767 This, lpMsgHdr, idGroup, bAnsi );
1769 /* Find the group */
1770 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1772 return DPERR_INVALIDPLAYER; /* yes player */
1775 context.This = (IDirectPlay3Impl*)This;
1776 context.bAnsi = bAnsi;
1777 context.idGroup = idGroup;
1779 /* Remove all players that this group has */
1780 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1781 cbRemoveGroupOrPlayer, &context, 0, bAnsi );
1783 /* Remove all links to groups that this group has since this is dp3 */
1784 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1785 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1787 /* Remove this group from the parent group - if it has one */
1788 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1789 ( lpGData->parent != DPID_SYSTEM_GROUP )
1792 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1793 idGroup );
1796 /* Now delete this group data and list from the system group */
1797 DP_DeleteGroup( This, idGroup );
1799 /* Let the SP know that we've destroyed this group */
1800 if( This->dp2->spData.lpCB->DeleteGroup )
1802 DPSP_DELETEGROUPDATA data;
1804 FIXME( "data.dwFlags is incorrect\n" );
1806 data.idGroup = idGroup;
1807 data.dwFlags = 0;
1808 data.lpISP = This->dp2->spData.lpISP;
1810 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1813 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1815 return DP_OK;
1818 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1819 ( LPDIRECTPLAY2A iface, DPID idGroup )
1821 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1822 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1825 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1826 ( LPDIRECTPLAY2 iface, DPID idGroup )
1828 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1829 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1832 typedef struct _DPFAGContext
1834 IDirectPlay2Impl* This;
1835 DPID idPlayer;
1836 BOOL bAnsi;
1837 } DPFAGContext, *lpDPFAGContext;
1839 static HRESULT DP_IF_DestroyPlayer
1840 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1842 DPFAGContext cbContext;
1844 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1845 This, lpMsgHdr, idPlayer, bAnsi );
1847 if( This->dp2->connectionInitialized == NO_PROVIDER )
1849 return DPERR_UNINITIALIZED;
1852 if( DP_FindPlayer( This, idPlayer ) == NULL )
1854 return DPERR_INVALIDPLAYER;
1857 /* FIXME: If the player is remote, we must be the host to delete this */
1859 cbContext.This = This;
1860 cbContext.idPlayer = idPlayer;
1861 cbContext.bAnsi = bAnsi;
1863 /* Find each group and call DeletePlayerFromGroup if the player is a
1864 member of the group */
1865 DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
1866 &cbContext, DPENUMGROUPS_ALL, bAnsi );
1868 /* Now delete player and player list from the sys group */
1869 DP_DeletePlayer( This, idPlayer );
1871 /* Let the SP know that we've destroyed this group */
1872 if( This->dp2->spData.lpCB->DeletePlayer )
1874 DPSP_DELETEPLAYERDATA data;
1876 FIXME( "data.dwFlags is incorrect\n" );
1878 data.idPlayer = idPlayer;
1879 data.dwFlags = 0;
1880 data.lpISP = This->dp2->spData.lpISP;
1882 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1885 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1887 return DP_OK;
1890 static BOOL CALLBACK
1891 cbDeletePlayerFromAllGroups(
1892 DPID dpId,
1893 DWORD dwPlayerType,
1894 LPCDPNAME lpName,
1895 DWORD dwFlags,
1896 LPVOID lpContext )
1898 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1900 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1902 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
1903 lpCtxt->bAnsi );
1905 /* Enumerate all groups in this group since this will normally only
1906 * be called for top level groups
1908 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
1909 dpId, NULL,
1910 cbDeletePlayerFromAllGroups,
1911 lpContext, DPENUMGROUPS_ALL,
1912 lpCtxt->bAnsi );
1915 else
1917 ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
1920 return TRUE;
1923 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
1924 ( LPDIRECTPLAY2A iface, DPID idPlayer )
1926 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1927 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1930 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1931 ( LPDIRECTPLAY2 iface, DPID idPlayer )
1933 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1934 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1937 static HRESULT DP_IF_EnumGroupPlayers
1938 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1939 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1940 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1942 lpGroupData lpGData;
1943 lpPlayerList lpPList;
1945 FIXME("(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
1946 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1947 lpContext, dwFlags, bAnsi );
1949 if( This->dp2->connectionInitialized == NO_PROVIDER )
1951 return DPERR_UNINITIALIZED;
1954 /* Find the group */
1955 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1957 return DPERR_INVALIDGROUP;
1960 if( DPQ_IS_EMPTY( lpGData->players ) )
1962 return DP_OK;
1965 lpPList = DPQ_FIRST( lpGData->players );
1967 /* Walk the players in this group */
1968 for( ;; )
1970 /* We do not enum the name server or app server as they are of no
1971 * consequence to the end user.
1973 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
1974 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
1978 /* FIXME: Need to add stuff for dwFlags checking */
1980 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1981 &lpPList->lpPData->name,
1982 lpPList->lpPData->dwFlags,
1983 lpContext )
1986 /* User requested break */
1987 return DP_OK;
1991 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
1993 break;
1996 lpPList = DPQ_NEXT( lpPList->players );
1999 return DP_OK;
2002 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
2003 ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
2004 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2005 LPVOID lpContext, DWORD dwFlags )
2007 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2008 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2009 lpEnumPlayersCallback2, lpContext,
2010 dwFlags, TRUE );
2013 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
2014 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
2015 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2016 LPVOID lpContext, DWORD dwFlags )
2018 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2019 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2020 lpEnumPlayersCallback2, lpContext,
2021 dwFlags, FALSE );
2024 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2025 static HRESULT DP_IF_EnumGroups
2026 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2027 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2028 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2030 return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2031 DPID_SYSTEM_GROUP, lpguidInstance,
2032 lpEnumPlayersCallback2, lpContext,
2033 dwFlags, bAnsi );
2036 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2037 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2038 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2039 LPVOID lpContext, DWORD dwFlags )
2041 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2042 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2043 lpContext, dwFlags, TRUE );
2046 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2047 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2048 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2049 LPVOID lpContext, DWORD dwFlags )
2051 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2052 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2053 lpContext, dwFlags, FALSE );
2056 static HRESULT DP_IF_EnumPlayers
2057 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2058 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2059 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2061 return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
2062 lpEnumPlayersCallback2, lpContext,
2063 dwFlags, bAnsi );
2066 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2067 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2068 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2069 LPVOID lpContext, DWORD dwFlags )
2071 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2072 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2073 lpContext, dwFlags, TRUE );
2076 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2077 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2078 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2079 LPVOID lpContext, DWORD dwFlags )
2081 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2082 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2083 lpContext, dwFlags, FALSE );
2086 /* This function should call the registered callback function that the user
2087 passed into EnumSessions for each entry available.
2089 static void DP_InvokeEnumSessionCallbacks
2090 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2091 LPVOID lpNSInfo,
2092 DWORD dwTimeout,
2093 LPVOID lpContext )
2095 LPDPSESSIONDESC2 lpSessionDesc;
2097 FIXME( ": not checking for conditions\n" );
2099 /* Not sure if this should be pruning but it's convenient */
2100 NS_PruneSessionCache( lpNSInfo );
2102 NS_ResetSessionEnumeration( lpNSInfo );
2104 /* Enumerate all sessions */
2105 /* FIXME: Need to indicate ANSI */
2106 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2108 TRACE( "EnumSessionsCallback2 invoked\n" );
2109 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2111 return;
2115 /* Invoke one last time to indicate that there is no more to come */
2116 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2119 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2121 EnumSessionAsyncCallbackData* data = lpContext;
2122 HANDLE hSuicideRequest = data->hSuicideRequest;
2123 DWORD dwTimeout = data->dwTimeout;
2125 TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
2127 for( ;; )
2129 HRESULT hr;
2131 /* Sleep up to dwTimeout waiting for request to terminate thread */
2132 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2134 TRACE( "Thread terminating on terminate request\n" );
2135 break;
2138 /* Now resend the enum request */
2139 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2140 data->dwEnumSessionFlags,
2141 data->lpSpData );
2143 if( FAILED(hr) )
2145 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2146 /* FIXME: Should we kill this thread? How to inform the main thread? */
2151 TRACE( "Thread terminating\n" );
2153 /* Clean up the thread data */
2154 CloseHandle( hSuicideRequest );
2155 HeapFree( GetProcessHeap(), 0, lpContext );
2157 /* FIXME: Need to have some notification to main app thread that this is
2158 * dead. It would serve two purposes. 1) allow sync on termination
2159 * so that we don't actually send something to ourselves when we
2160 * become name server (race condition) and 2) so that if we die
2161 * abnormally something else will be able to tell.
2164 return 1;
2167 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
2169 /* Does a thread exist? If so we were doing an async enum session */
2170 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2172 TRACE( "Killing EnumSession thread %p\n",
2173 This->dp2->hEnumSessionThread );
2175 /* Request that the thread kill itself nicely */
2176 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2177 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2179 /* We no longer need to know about the thread */
2180 CloseHandle( This->dp2->hEnumSessionThread );
2182 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2186 static HRESULT DP_IF_EnumSessions
2187 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2188 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2189 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2191 HRESULT hr = DP_OK;
2193 TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x,%u)\n",
2194 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2195 bAnsi );
2196 if( This->dp2->connectionInitialized == NO_PROVIDER )
2198 return DPERR_UNINITIALIZED;
2201 /* Can't enumerate if the interface is already open */
2202 if( This->dp2->bConnectionOpen )
2204 return DPERR_GENERIC;
2207 #if 1
2208 /* The loading of a lobby provider _seems_ to require a backdoor loading
2209 * of the service provider to also associate with this DP object. This is
2210 * because the app doesn't seem to have to call EnumConnections and
2211 * InitializeConnection for the SP before calling this method. As such
2212 * we'll do their dirty work for them with a quick hack so as to always
2213 * load the TCP/IP service provider.
2215 * The correct solution would seem to involve creating a dialog box which
2216 * contains the possible SPs. These dialog boxes most likely follow SDK
2217 * examples.
2219 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2221 LPVOID lpConnection;
2222 DWORD dwSize;
2224 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2226 if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2228 ERR( "Can't build compound addr\n" );
2229 return DPERR_GENERIC;
2232 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2233 0, bAnsi );
2234 if( FAILED(hr) )
2236 return hr;
2239 /* Free up the address buffer */
2240 HeapFree( GetProcessHeap(), 0, lpConnection );
2242 /* The SP is now initialized */
2243 This->dp2->bSPInitialized = TRUE;
2245 #endif
2248 /* Use the service provider default? */
2249 if( dwTimeout == 0 )
2251 DPCAPS spCaps;
2252 spCaps.dwSize = sizeof( spCaps );
2254 DP_IF_GetCaps( This, &spCaps, 0 );
2255 dwTimeout = spCaps.dwTimeout;
2257 /* The service provider doesn't provide one either! */
2258 if( dwTimeout == 0 )
2260 /* Provide the TCP/IP default */
2261 dwTimeout = DPMSG_WAIT_5_SECS;
2265 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2267 DP_KillEnumSessionThread( This );
2268 return hr;
2271 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2273 /* Enumerate everything presently in the local session cache */
2274 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2275 This->dp2->lpNameServerData, dwTimeout,
2276 lpContext );
2278 if( This->dp2->dwEnumSessionLock != 0 )
2279 return DPERR_CONNECTING;
2281 /* See if we've already created a thread to service this interface */
2282 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2284 DWORD dwThreadId;
2285 This->dp2->dwEnumSessionLock++;
2287 /* Send the first enum request inline since the user may cancel a dialog
2288 * if one is presented. Also, may also have a connecting return code.
2290 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2291 dwFlags, &This->dp2->spData );
2293 if( SUCCEEDED(hr) )
2295 EnumSessionAsyncCallbackData* lpData
2296 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2297 /* FIXME: need to kill the thread on object deletion */
2298 lpData->lpSpData = &This->dp2->spData;
2300 lpData->requestGuid = lpsd->guidApplication;
2301 lpData->dwEnumSessionFlags = dwFlags;
2302 lpData->dwTimeout = dwTimeout;
2304 This->dp2->hKillEnumSessionThreadEvent =
2305 CreateEventW( NULL, TRUE, FALSE, NULL );
2307 if( !DuplicateHandle( GetCurrentProcess(),
2308 This->dp2->hKillEnumSessionThreadEvent,
2309 GetCurrentProcess(),
2310 &lpData->hSuicideRequest,
2311 0, FALSE, DUPLICATE_SAME_ACCESS )
2314 ERR( "Can't duplicate thread killing handle\n" );
2317 TRACE( ": creating EnumSessionsRequest thread\n" );
2319 This->dp2->hEnumSessionThread = CreateThread( NULL,
2321 DP_EnumSessionsSendAsyncRequestThread,
2322 lpData,
2324 &dwThreadId );
2326 This->dp2->dwEnumSessionLock--;
2329 else
2331 /* Invalidate the session cache for the interface */
2332 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2334 /* Send the broadcast for session enumeration */
2335 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2336 dwFlags,
2337 &This->dp2->spData );
2340 SleepEx( dwTimeout, FALSE );
2342 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2343 This->dp2->lpNameServerData, dwTimeout,
2344 lpContext );
2347 return hr;
2350 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2351 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2352 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2353 LPVOID lpContext, DWORD dwFlags )
2355 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2356 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2357 lpContext, dwFlags, TRUE );
2360 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2361 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2362 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2363 LPVOID lpContext, DWORD dwFlags )
2365 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2366 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2367 lpContext, dwFlags, FALSE );
2370 static HRESULT DP_IF_GetPlayerCaps
2371 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2372 DWORD dwFlags )
2374 DPSP_GETCAPSDATA data;
2376 TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
2378 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2380 return DPERR_UNINITIALIZED;
2383 /* Query the service provider */
2384 data.idPlayer = idPlayer;
2385 data.dwFlags = dwFlags;
2386 data.lpCaps = lpDPCaps;
2387 data.lpISP = This->dp2->spData.lpISP;
2389 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2392 static HRESULT DP_IF_GetCaps
2393 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2395 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2398 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2399 ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2401 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2402 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2405 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2406 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2408 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2409 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2412 static HRESULT DP_IF_GetGroupData
2413 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2414 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2416 lpGroupData lpGData;
2417 DWORD dwRequiredBufferSize;
2418 LPVOID lpCopyDataFrom;
2420 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2421 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2423 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2425 return DPERR_INVALIDGROUP;
2428 /* How much buffer is required? */
2429 if( dwFlags & DPSET_LOCAL )
2431 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2432 lpCopyDataFrom = lpGData->lpLocalData;
2434 else
2436 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2437 lpCopyDataFrom = lpGData->lpRemoteData;
2440 /* Is the user requesting to know how big a buffer is required? */
2441 if( ( lpData == NULL ) ||
2442 ( *lpdwDataSize < dwRequiredBufferSize )
2445 *lpdwDataSize = dwRequiredBufferSize;
2446 return DPERR_BUFFERTOOSMALL;
2449 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2451 return DP_OK;
2454 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2455 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2456 LPDWORD lpdwDataSize, DWORD dwFlags )
2458 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2459 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2460 dwFlags, TRUE );
2463 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2464 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2465 LPDWORD lpdwDataSize, DWORD dwFlags )
2467 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2468 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2469 dwFlags, FALSE );
2472 static HRESULT DP_IF_GetGroupName
2473 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2474 LPDWORD lpdwDataSize, BOOL bAnsi )
2476 lpGroupData lpGData;
2477 LPDPNAME lpName = lpData;
2478 DWORD dwRequiredDataSize;
2480 FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2481 This, idGroup, lpData, lpdwDataSize, bAnsi );
2483 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2485 return DPERR_INVALIDGROUP;
2488 dwRequiredDataSize = lpGData->name.dwSize;
2490 if( lpGData->name.u1.lpszShortNameA )
2492 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2495 if( lpGData->name.u2.lpszLongNameA )
2497 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2500 if( ( lpData == NULL ) ||
2501 ( *lpdwDataSize < dwRequiredDataSize )
2504 *lpdwDataSize = dwRequiredDataSize;
2505 return DPERR_BUFFERTOOSMALL;
2508 /* Copy the structure */
2509 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2511 if( lpGData->name.u1.lpszShortNameA )
2513 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2514 lpGData->name.u1.lpszShortNameA );
2516 else
2518 lpName->u1.lpszShortNameA = NULL;
2521 if( lpGData->name.u1.lpszShortNameA )
2523 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2524 lpGData->name.u2.lpszLongNameA );
2526 else
2528 lpName->u2.lpszLongNameA = NULL;
2531 return DP_OK;
2534 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2535 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2536 LPDWORD lpdwDataSize )
2538 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2539 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2542 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2543 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2544 LPDWORD lpdwDataSize )
2546 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2547 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2550 static HRESULT DP_IF_GetMessageCount
2551 ( IDirectPlay2Impl* This, DPID idPlayer,
2552 LPDWORD lpdwCount, BOOL bAnsi )
2554 FIXME("(%p)->(0x%08x,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2555 return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2556 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2557 bAnsi );
2560 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2561 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2563 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2564 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2567 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2568 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2570 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2571 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2574 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2575 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2577 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2578 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2579 return DP_OK;
2582 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2583 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2585 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2586 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2587 return DP_OK;
2590 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2591 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2592 DWORD dwFlags )
2594 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2595 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2598 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2599 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2600 DWORD dwFlags )
2602 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2603 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2606 static HRESULT DP_IF_GetPlayerData
2607 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2608 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2610 lpPlayerList lpPList;
2611 DWORD dwRequiredBufferSize;
2612 LPVOID lpCopyDataFrom;
2614 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2615 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2617 if( This->dp2->connectionInitialized == NO_PROVIDER )
2619 return DPERR_UNINITIALIZED;
2622 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2624 return DPERR_INVALIDPLAYER;
2627 /* How much buffer is required? */
2628 if( dwFlags & DPSET_LOCAL )
2630 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2631 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2633 else
2635 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2636 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2639 /* Is the user requesting to know how big a buffer is required? */
2640 if( ( lpData == NULL ) ||
2641 ( *lpdwDataSize < dwRequiredBufferSize )
2644 *lpdwDataSize = dwRequiredBufferSize;
2645 return DPERR_BUFFERTOOSMALL;
2648 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2650 return DP_OK;
2653 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2654 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2655 LPDWORD lpdwDataSize, DWORD dwFlags )
2657 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2658 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2659 dwFlags, TRUE );
2662 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2663 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2664 LPDWORD lpdwDataSize, DWORD dwFlags )
2666 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2667 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2668 dwFlags, FALSE );
2671 static HRESULT DP_IF_GetPlayerName
2672 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2673 LPDWORD lpdwDataSize, BOOL bAnsi )
2675 lpPlayerList lpPList;
2676 LPDPNAME lpName = lpData;
2677 DWORD dwRequiredDataSize;
2679 FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2680 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2682 if( This->dp2->connectionInitialized == NO_PROVIDER )
2684 return DPERR_UNINITIALIZED;
2687 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2689 return DPERR_INVALIDPLAYER;
2692 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2694 if( lpPList->lpPData->name.u1.lpszShortNameA )
2696 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2699 if( lpPList->lpPData->name.u2.lpszLongNameA )
2701 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2704 if( ( lpData == NULL ) ||
2705 ( *lpdwDataSize < dwRequiredDataSize )
2708 *lpdwDataSize = dwRequiredDataSize;
2709 return DPERR_BUFFERTOOSMALL;
2712 /* Copy the structure */
2713 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2715 if( lpPList->lpPData->name.u1.lpszShortNameA )
2717 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2718 lpPList->lpPData->name.u1.lpszShortNameA );
2720 else
2722 lpName->u1.lpszShortNameA = NULL;
2725 if( lpPList->lpPData->name.u1.lpszShortNameA )
2727 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2728 lpPList->lpPData->name.u2.lpszLongNameA );
2730 else
2732 lpName->u2.lpszLongNameA = NULL;
2735 return DP_OK;
2738 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2739 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2740 LPDWORD lpdwDataSize )
2742 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2743 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2746 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2747 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2748 LPDWORD lpdwDataSize )
2750 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2751 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2754 static HRESULT DP_GetSessionDesc
2755 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2756 BOOL bAnsi )
2758 DWORD dwRequiredSize;
2760 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2762 if( This->dp2->connectionInitialized == NO_PROVIDER )
2764 return DPERR_UNINITIALIZED;
2767 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2769 return DPERR_INVALIDPARAMS;
2772 /* FIXME: Get from This->dp2->lpSessionDesc */
2773 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2775 if ( ( lpData == NULL ) ||
2776 ( *lpdwDataSize < dwRequiredSize )
2779 *lpdwDataSize = dwRequiredSize;
2780 return DPERR_BUFFERTOOSMALL;
2783 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2785 return DP_OK;
2788 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2789 ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2791 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2792 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2795 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2796 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2798 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2799 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2802 /* Intended only for COM compatibility. Always returns an error. */
2803 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2804 ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2806 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2807 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2808 return DPERR_ALREADYINITIALIZED;
2811 /* Intended only for COM compatibility. Always returns an error. */
2812 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2813 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2815 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2816 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2817 return DPERR_ALREADYINITIALIZED;
2821 static HRESULT DP_SecureOpen
2822 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2823 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2824 BOOL bAnsi )
2826 HRESULT hr = DP_OK;
2828 FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2829 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2831 if( This->dp2->connectionInitialized == NO_PROVIDER )
2833 return DPERR_UNINITIALIZED;
2836 if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
2838 TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
2839 return DPERR_INVALIDPARAMS;
2842 if( This->dp2->bConnectionOpen )
2844 TRACE( ": rejecting already open connection.\n" );
2845 return DPERR_ALREADYINITIALIZED;
2848 /* If we're enumerating, kill the thread */
2849 DP_KillEnumSessionThread( This );
2851 if( dwFlags & DPOPEN_CREATE )
2853 /* Rightoo - this computer is the host and the local computer needs to be
2854 the name server so that others can join this session */
2855 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2857 This->dp2->bHostInterface = TRUE;
2859 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2860 if( FAILED( hr ) )
2862 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2863 return hr;
2867 /* Invoke the conditional callback for the service provider */
2868 if( This->dp2->spData.lpCB->Open )
2870 DPSP_OPENDATA data;
2872 FIXME( "Not all data fields are correct. Need new parameter\n" );
2874 data.bCreate = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
2875 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2876 : NS_GetNSAddr( This->dp2->lpNameServerData );
2877 data.lpISP = This->dp2->spData.lpISP;
2878 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
2879 data.dwOpenFlags = dwFlags;
2880 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2882 hr = (*This->dp2->spData.lpCB->Open)(&data);
2883 if( FAILED( hr ) )
2885 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2886 return hr;
2891 /* Create the system group of which everything is a part of */
2892 DPID systemGroup = DPID_SYSTEM_GROUP;
2894 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2895 NULL, 0, 0, TRUE );
2899 if( dwFlags & DPOPEN_JOIN )
2901 DPID dpidServerId = DPID_UNKNOWN;
2903 /* Create the server player for this interface. This way we can receive
2904 * messages for this session.
2906 /* FIXME: I suppose that we should be setting an event for a receive
2907 * type of thing. That way the messaging thread could know to wake
2908 * up. DPlay would then trigger the hEvent for the player the
2909 * message is directed to.
2911 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2913 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2916 else if( dwFlags & DPOPEN_CREATE )
2918 DPID dpidNameServerId = DPID_NAME_SERVER;
2920 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2921 0, DPPLAYER_SERVERPLAYER, bAnsi );
2924 if( FAILED(hr) )
2926 ERR( "Couldn't create name server/system player: %s\n",
2927 DPLAYX_HresultToString(hr) );
2930 return hr;
2933 static HRESULT WINAPI DirectPlay2AImpl_Open
2934 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2936 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2937 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2938 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
2941 static HRESULT WINAPI DirectPlay2WImpl_Open
2942 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2944 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2945 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2946 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
2949 static HRESULT DP_IF_Receive
2950 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2951 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2953 LPDPMSG lpMsg = NULL;
2955 FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
2956 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2958 if( This->dp2->connectionInitialized == NO_PROVIDER )
2960 return DPERR_UNINITIALIZED;
2963 if( dwFlags == 0 )
2965 dwFlags = DPRECEIVE_ALL;
2968 /* If the lpData is NULL, we must be peeking the message */
2969 if( ( lpData == NULL ) &&
2970 !( dwFlags & DPRECEIVE_PEEK )
2973 return DPERR_INVALIDPARAMS;
2976 if( dwFlags & DPRECEIVE_ALL )
2978 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2980 if( !( dwFlags & DPRECEIVE_PEEK ) )
2982 FIXME( "Remove from queue\n" );
2985 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2986 ( dwFlags & DPRECEIVE_FROMPLAYER )
2989 FIXME( "Find matching message 0x%08x\n", dwFlags );
2991 else
2993 ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
2996 if( lpMsg == NULL )
2998 return DPERR_NOMESSAGES;
3001 /* Copy into the provided buffer */
3002 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
3004 return DP_OK;
3007 static HRESULT WINAPI DirectPlay2AImpl_Receive
3008 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
3009 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3011 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3012 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3013 lpData, lpdwDataSize, TRUE );
3016 static HRESULT WINAPI DirectPlay2WImpl_Receive
3017 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
3018 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3020 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3021 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3022 lpData, lpdwDataSize, FALSE );
3025 static HRESULT WINAPI DirectPlay2AImpl_Send
3026 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3028 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3029 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3030 0, 0, NULL, NULL, TRUE );
3033 static HRESULT WINAPI DirectPlay2WImpl_Send
3034 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3036 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3037 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3038 0, 0, NULL, NULL, FALSE );
3041 static HRESULT DP_IF_SetGroupData
3042 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3043 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3045 lpGroupData lpGData;
3047 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3048 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3050 /* Parameter check */
3051 if( ( lpData == NULL ) &&
3052 ( dwDataSize != 0 )
3055 return DPERR_INVALIDPARAMS;
3058 /* Find the pointer to the data for this player */
3059 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3061 return DPERR_INVALIDOBJECT;
3064 if( !(dwFlags & DPSET_LOCAL) )
3066 FIXME( "Was this group created by this interface?\n" );
3067 /* FIXME: If this is a remote update need to allow it but not
3068 * send a message.
3072 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3074 /* FIXME: Only send a message if this group is local to the session otherwise
3075 * it will have been rejected above
3077 if( !(dwFlags & DPSET_LOCAL) )
3079 FIXME( "Send msg?\n" );
3082 return DP_OK;
3085 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3086 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3087 DWORD dwDataSize, DWORD dwFlags )
3089 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3090 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3093 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3094 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3095 DWORD dwDataSize, DWORD dwFlags )
3097 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3098 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3101 static HRESULT DP_IF_SetGroupName
3102 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3103 DWORD dwFlags, BOOL bAnsi )
3105 lpGroupData lpGData;
3107 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3108 lpGroupName, dwFlags, bAnsi );
3110 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3112 return DPERR_INVALIDGROUP;
3115 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3117 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3118 FIXME( "Message not sent and dwFlags ignored\n" );
3120 return DP_OK;
3123 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3124 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3125 DWORD dwFlags )
3127 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3128 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3131 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3132 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3133 DWORD dwFlags )
3135 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3136 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3139 static HRESULT DP_IF_SetPlayerData
3140 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3141 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3143 lpPlayerList lpPList;
3145 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3146 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3148 if( This->dp2->connectionInitialized == NO_PROVIDER )
3150 return DPERR_UNINITIALIZED;
3153 /* Parameter check */
3154 if( ( lpData == NULL ) &&
3155 ( dwDataSize != 0 )
3158 return DPERR_INVALIDPARAMS;
3161 /* Find the pointer to the data for this player */
3162 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3164 return DPERR_INVALIDPLAYER;
3167 if( !(dwFlags & DPSET_LOCAL) )
3169 FIXME( "Was this group created by this interface?\n" );
3170 /* FIXME: If this is a remote update need to allow it but not
3171 * send a message.
3175 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3177 if( !(dwFlags & DPSET_LOCAL) )
3179 FIXME( "Send msg?\n" );
3182 return DP_OK;
3185 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3186 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3187 DWORD dwDataSize, DWORD dwFlags )
3189 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3190 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3191 dwFlags, TRUE );
3194 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3195 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3196 DWORD dwDataSize, DWORD dwFlags )
3198 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3199 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3200 dwFlags, FALSE );
3203 static HRESULT DP_IF_SetPlayerName
3204 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3205 DWORD dwFlags, BOOL bAnsi )
3207 lpPlayerList lpPList;
3209 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3210 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3212 if( This->dp2->connectionInitialized == NO_PROVIDER )
3214 return DPERR_UNINITIALIZED;
3217 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3219 return DPERR_INVALIDGROUP;
3222 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3224 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3225 FIXME( "Message not sent and dwFlags ignored\n" );
3227 return DP_OK;
3230 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3231 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3232 DWORD dwFlags )
3234 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3235 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3238 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3239 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3240 DWORD dwFlags )
3242 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3243 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3246 static HRESULT DP_SetSessionDesc
3247 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3248 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3250 DWORD dwRequiredSize;
3251 LPDPSESSIONDESC2 lpTempSessDesc;
3253 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3254 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3256 if( This->dp2->connectionInitialized == NO_PROVIDER )
3258 return DPERR_UNINITIALIZED;
3261 if( dwFlags )
3263 return DPERR_INVALIDPARAMS;
3266 /* Only the host is allowed to update the session desc */
3267 if( !This->dp2->bHostInterface )
3269 return DPERR_ACCESSDENIED;
3272 /* FIXME: Copy into This->dp2->lpSessionDesc */
3273 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3274 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3276 if( lpTempSessDesc == NULL )
3278 return DPERR_OUTOFMEMORY;
3281 /* Free the old */
3282 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3284 This->dp2->lpSessionDesc = lpTempSessDesc;
3285 /* Set the new */
3286 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3287 if( bInitial )
3289 /*Initializing session GUID*/
3290 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3292 /* If this is an external invocation of the interface, we should be
3293 * letting everyone know that things have changed. Otherwise this is
3294 * just an initialization and it doesn't need to be propagated.
3296 if( !bInitial )
3298 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3301 return DP_OK;
3304 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3305 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3307 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3308 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3311 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3312 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3314 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3315 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3318 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3319 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3321 DWORD dwSize = 0;
3323 if( lpSessDesc == NULL )
3325 /* Hmmm..don't need any size? */
3326 ERR( "NULL lpSessDesc\n" );
3327 return dwSize;
3330 dwSize += sizeof( *lpSessDesc );
3332 if( bAnsi )
3334 if( lpSessDesc->u1.lpszSessionNameA )
3336 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3339 if( lpSessDesc->u2.lpszPasswordA )
3341 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3344 else /* UNICODE */
3346 if( lpSessDesc->u1.lpszSessionName )
3348 dwSize += sizeof( WCHAR ) *
3349 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3352 if( lpSessDesc->u2.lpszPassword )
3354 dwSize += sizeof( WCHAR ) *
3355 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3359 return dwSize;
3362 /* Assumes that contiguous buffers are already allocated. */
3363 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3364 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3366 BYTE* lpStartOfFreeSpace;
3368 if( lpSessionDest == NULL )
3370 ERR( "NULL lpSessionDest\n" );
3371 return;
3374 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3376 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3378 if( bAnsi )
3380 if( lpSessionSrc->u1.lpszSessionNameA )
3382 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3383 lpSessionDest->u1.lpszSessionNameA );
3384 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3385 lpStartOfFreeSpace +=
3386 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3389 if( lpSessionSrc->u2.lpszPasswordA )
3391 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3392 lpSessionDest->u2.lpszPasswordA );
3393 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3394 lpStartOfFreeSpace +=
3395 lstrlenA( lpSessionDest->u2.lpszPasswordA ) + 1;
3398 else /* UNICODE */
3400 if( lpSessionSrc->u1.lpszSessionName )
3402 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3403 lpSessionDest->u1.lpszSessionName );
3404 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3405 lpStartOfFreeSpace += sizeof(WCHAR) *
3406 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3409 if( lpSessionSrc->u2.lpszPassword )
3411 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3412 lpSessionDest->u2.lpszPassword );
3413 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3414 lpStartOfFreeSpace += sizeof(WCHAR) *
3415 ( lstrlenW( lpSessionDest->u2.lpszPassword ) + 1 );
3421 static HRESULT DP_IF_AddGroupToGroup
3422 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3424 lpGroupData lpGData;
3425 lpGroupList lpNewGList;
3427 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3429 if( This->dp2->connectionInitialized == NO_PROVIDER )
3431 return DPERR_UNINITIALIZED;
3434 if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3436 return DPERR_INVALIDGROUP;
3439 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3441 return DPERR_INVALIDGROUP;
3444 /* Create a player list (ie "shortcut" ) */
3445 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3446 if( lpNewGList == NULL )
3448 return DPERR_CANTADDPLAYER;
3451 /* Add the shortcut */
3452 lpGData->uRef++;
3453 lpNewGList->lpGData = lpGData;
3455 /* Add the player to the list of players for this group */
3456 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3458 /* Send a ADDGROUPTOGROUP message */
3459 FIXME( "Not sending message\n" );
3461 return DP_OK;
3464 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3465 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3467 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3468 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3471 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3472 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3474 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3475 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3478 static HRESULT DP_IF_CreateGroupInGroup
3479 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3480 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3481 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3483 lpGroupData lpGParentData;
3484 lpGroupList lpGList;
3485 lpGroupData lpGData;
3487 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3488 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3489 dwDataSize, dwFlags, bAnsi );
3491 if( This->dp2->connectionInitialized == NO_PROVIDER )
3493 return DPERR_UNINITIALIZED;
3496 /* Verify that the specified parent is valid */
3497 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3498 idParentGroup ) ) == NULL
3501 return DPERR_INVALIDGROUP;
3504 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3505 dwFlags, idParentGroup, bAnsi );
3507 if( lpGData == NULL )
3509 return DPERR_CANTADDPLAYER; /* yes player not group */
3512 /* Something else is referencing this data */
3513 lpGData->uRef++;
3515 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3517 /* The list has now been inserted into the interface group list. We now
3518 need to put a "shortcut" to this group in the parent group */
3519 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3520 if( lpGList == NULL )
3522 FIXME( "Memory leak\n" );
3523 return DPERR_CANTADDPLAYER; /* yes player not group */
3526 lpGList->lpGData = lpGData;
3528 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3530 /* Let the SP know that we've created this group */
3531 if( This->dp2->spData.lpCB->CreateGroup )
3533 DPSP_CREATEGROUPDATA data;
3535 TRACE( "Calling SP CreateGroup\n" );
3537 data.idGroup = *lpidGroup;
3538 data.dwFlags = dwFlags;
3539 data.lpSPMessageHeader = lpMsgHdr;
3540 data.lpISP = This->dp2->spData.lpISP;
3542 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3545 /* Inform all other peers of the creation of a new group. If there are
3546 * no peers keep this quiet.
3548 if( This->dp2->lpSessionDesc &&
3549 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3551 DPMSG_CREATEPLAYERORGROUP msg;
3553 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3554 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3555 msg.dpId = *lpidGroup;
3556 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3557 msg.lpData = lpData;
3558 msg.dwDataSize = dwDataSize;
3559 msg.dpnName = *lpGroupName;
3561 /* FIXME: Correct to just use send effectively? */
3562 /* FIXME: Should size include data w/ message or just message "header" */
3563 /* FIXME: Check return code */
3564 DP_SendEx( (IDirectPlay2Impl*)This,
3565 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3566 0, 0, NULL, NULL, bAnsi );
3569 return DP_OK;
3572 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3573 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3574 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3575 DWORD dwFlags )
3577 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3579 *lpidGroup = DPID_UNKNOWN;
3581 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3582 lpGroupName, lpData, dwDataSize, dwFlags,
3583 TRUE );
3586 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3587 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3588 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3589 DWORD dwFlags )
3591 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3593 *lpidGroup = DPID_UNKNOWN;
3595 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3596 lpGroupName, lpData, dwDataSize,
3597 dwFlags, FALSE );
3600 static HRESULT DP_IF_DeleteGroupFromGroup
3601 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3603 lpGroupList lpGList;
3604 lpGroupData lpGParentData;
3606 TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3608 /* Is the parent group valid? */
3609 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3611 return DPERR_INVALIDGROUP;
3614 /* Remove the group from the parent group queue */
3615 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3617 if( lpGList == NULL )
3619 return DPERR_INVALIDGROUP;
3622 /* Decrement the ref count */
3623 lpGList->lpGData->uRef--;
3625 /* Free up the list item */
3626 HeapFree( GetProcessHeap(), 0, lpGList );
3628 /* Should send a DELETEGROUPFROMGROUP message */
3629 FIXME( "message not sent\n" );
3631 return DP_OK;
3634 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3635 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3637 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3638 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3641 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3642 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3644 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3645 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3648 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3649 LPDWORD lpdwBufSize )
3651 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3652 HRESULT hr;
3654 dpCompoundAddress.dwDataSize = sizeof( GUID );
3655 dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3656 dpCompoundAddress.lpData = lpcSpGuid;
3658 *lplpAddrBuf = NULL;
3659 *lpdwBufSize = 0;
3661 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3662 lpdwBufSize, TRUE );
3664 if( hr != DPERR_BUFFERTOOSMALL )
3666 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3667 return FALSE;
3670 /* Now allocate the buffer */
3671 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3672 *lpdwBufSize );
3674 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3675 lpdwBufSize, TRUE );
3676 if( FAILED(hr) )
3678 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3679 return FALSE;
3682 return TRUE;
3685 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
3686 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3688 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3689 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3691 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3692 if( dwFlags == 0 )
3694 dwFlags = DPCONNECTION_DIRECTPLAY;
3697 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3698 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3701 return DPERR_INVALIDFLAGS;
3704 if( !lpEnumCallback )
3706 return DPERR_INVALIDPARAMS;
3709 /* Enumerate DirectPlay service providers */
3710 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3712 HKEY hkResult;
3713 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3714 LPCSTR guidDataSubKey = "Guid";
3715 char subKeyName[51];
3716 DWORD dwIndex, sizeOfSubKeyName=50;
3717 FILETIME filetime;
3719 /* Need to loop over the service providers in the registry */
3720 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3721 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3723 /* Hmmm. Does this mean that there are no service providers? */
3724 ERR(": no service providers?\n");
3725 return DP_OK;
3729 /* Traverse all the service providers we have available */
3730 for( dwIndex=0;
3731 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3732 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3733 ++dwIndex, sizeOfSubKeyName=51 )
3736 HKEY hkServiceProvider;
3737 GUID serviceProviderGUID;
3738 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3739 char returnBuffer[51];
3740 WCHAR buff[51];
3741 DPNAME dpName;
3742 BOOL bBuildPass;
3744 LPVOID lpAddressBuffer = NULL;
3745 DWORD dwAddressBufferSize = 0;
3747 TRACE(" this time through: %s\n", subKeyName );
3749 /* Get a handle for this particular service provider */
3750 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3751 &hkServiceProvider ) != ERROR_SUCCESS )
3753 ERR(": what the heck is going on?\n" );
3754 continue;
3757 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3758 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3759 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3761 ERR(": missing GUID registry data members\n" );
3762 RegCloseKey(hkServiceProvider);
3763 continue;
3765 RegCloseKey(hkServiceProvider);
3767 /* FIXME: Check return types to ensure we're interpreting data right */
3768 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3769 CLSIDFromString( buff, &serviceProviderGUID );
3770 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3772 /* Fill in the DPNAME struct for the service provider */
3773 dpName.dwSize = sizeof( dpName );
3774 dpName.dwFlags = 0;
3775 dpName.u1.lpszShortNameA = subKeyName;
3776 dpName.u2.lpszLongNameA = NULL;
3778 /* Create the compound address for the service provider.
3779 * NOTE: This is a gruesome architectural scar right now. DP
3780 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3781 * native dll just gets around this little bit by allocating an
3782 * 80 byte buffer which isn't even filled with a valid compound
3783 * address. Oh well. Creating a proper compound address is the
3784 * way to go anyways despite this method taking slightly more
3785 * heap space and realtime :) */
3787 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3788 &lpAddressBuffer,
3789 &dwAddressBufferSize );
3790 if( !bBuildPass )
3792 ERR( "Can't build compound addr\n" );
3793 return DPERR_GENERIC;
3796 /* The enumeration will return FALSE if we are not to continue */
3797 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3798 &dpName, dwFlags, lpContext ) )
3800 return DP_OK;
3805 /* Enumerate DirectPlayLobby service providers */
3806 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3808 HKEY hkResult;
3809 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3810 LPCSTR guidDataSubKey = "Guid";
3811 char subKeyName[51];
3812 DWORD dwIndex, sizeOfSubKeyName=50;
3813 FILETIME filetime;
3815 /* Need to loop over the service providers in the registry */
3816 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3817 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3819 /* Hmmm. Does this mean that there are no service providers? */
3820 ERR(": no service providers?\n");
3821 return DP_OK;
3825 /* Traverse all the lobby providers we have available */
3826 for( dwIndex=0;
3827 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3828 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3829 ++dwIndex, sizeOfSubKeyName=51 )
3832 HKEY hkServiceProvider;
3833 GUID serviceProviderGUID;
3834 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3835 char returnBuffer[51];
3836 WCHAR buff[51];
3837 DPNAME dpName;
3838 HRESULT hr;
3840 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3841 LPVOID lpAddressBuffer = NULL;
3842 DWORD dwAddressBufferSize = 0;
3844 TRACE(" this time through: %s\n", subKeyName );
3846 /* Get a handle for this particular service provider */
3847 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3848 &hkServiceProvider ) != ERROR_SUCCESS )
3850 ERR(": what the heck is going on?\n" );
3851 continue;
3854 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3855 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3856 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3858 ERR(": missing GUID registry data members\n" );
3859 RegCloseKey(hkServiceProvider);
3860 continue;
3862 RegCloseKey(hkServiceProvider);
3864 /* FIXME: Check return types to ensure we're interpreting data right */
3865 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3866 CLSIDFromString( buff, &serviceProviderGUID );
3867 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3869 /* Fill in the DPNAME struct for the service provider */
3870 dpName.dwSize = sizeof( dpName );
3871 dpName.dwFlags = 0;
3872 dpName.u1.lpszShortNameA = subKeyName;
3873 dpName.u2.lpszLongNameA = NULL;
3875 /* Create the compound address for the service provider.
3876 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3877 nast stuff. This may be why the native dll just gets around this little bit by
3878 allocating an 80 byte buffer which isn't even a filled with a valid compound
3879 address. Oh well. Creating a proper compound address is the way to go anyways
3880 despite this method taking slightly more heap space and realtime :) */
3882 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3883 dpCompoundAddress.dwDataSize = sizeof( GUID );
3884 dpCompoundAddress.lpData = &serviceProviderGUID;
3886 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3887 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3889 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3890 return hr;
3893 /* Now allocate the buffer */
3894 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3896 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3897 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3899 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3900 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3901 return hr;
3904 /* The enumeration will return FALSE if we are not to continue */
3905 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3906 &dpName, dwFlags, lpContext ) )
3908 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3909 return DP_OK;
3911 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3915 return DP_OK;
3918 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3919 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3921 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3922 FIXME("(%p)->(%p,%p,%p,0x%08x): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3923 return DP_OK;
3926 static HRESULT DP_IF_EnumGroupsInGroup
3927 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3928 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3929 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3931 lpGroupList lpGList;
3932 lpGroupData lpGData;
3934 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
3935 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3936 lpContext, dwFlags, bAnsi );
3938 if( This->dp2->connectionInitialized == NO_PROVIDER )
3940 return DPERR_UNINITIALIZED;
3943 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3945 return DPERR_INVALIDGROUP;
3948 if( DPQ_IS_EMPTY( lpGData->groups ) )
3950 return DP_OK;
3953 lpGList = DPQ_FIRST( lpGData->groups );
3955 for( ;; )
3957 /* FIXME: Should check dwFlags for match here */
3959 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3960 &lpGList->lpGData->name, dwFlags,
3961 lpContext ) )
3963 return DP_OK; /* User requested break */
3966 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3968 break;
3971 lpGList = DPQ_NEXT( lpGList->groups );
3975 return DP_OK;
3978 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
3979 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3980 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3981 DWORD dwFlags )
3983 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3984 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3985 lpEnumPlayersCallback2, lpContext, dwFlags,
3986 TRUE );
3989 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3990 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3991 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3992 DWORD dwFlags )
3994 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3995 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3996 lpEnumPlayersCallback2, lpContext, dwFlags,
3997 FALSE );
4000 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
4001 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4003 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4004 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4005 return DP_OK;
4008 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
4009 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4011 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4012 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4013 return DP_OK;
4016 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
4017 REFGUID guidDataType,
4018 DWORD dwDataSize,
4019 LPCVOID lpData,
4020 LPVOID lpContext )
4022 /* Looking for the GUID of the provider to load */
4023 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
4024 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
4027 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4028 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
4030 if( dwDataSize != sizeof( GUID ) )
4032 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4035 memcpy( lpContext, lpData, dwDataSize );
4037 /* There shouldn't be more than 1 GUID/compound address */
4038 return FALSE;
4041 /* Still waiting for what we want */
4042 return TRUE;
4046 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4047 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4049 UINT i;
4050 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4051 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4052 LPCSTR guidDataSubKey = "Guid";
4053 LPCSTR majVerDataSubKey = "dwReserved1";
4054 LPCSTR minVerDataSubKey = "dwReserved2";
4055 LPCSTR pathSubKey = "Path";
4057 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4059 /* FIXME: Cloned code with a quick hack. */
4060 for( i=0; i<2; i++ )
4062 HKEY hkResult;
4063 LPCSTR searchSubKey;
4064 char subKeyName[51];
4065 DWORD dwIndex, sizeOfSubKeyName=50;
4066 FILETIME filetime;
4068 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4069 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4072 /* Need to loop over the service providers in the registry */
4073 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4074 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4076 /* Hmmm. Does this mean that there are no service providers? */
4077 ERR(": no service providers?\n");
4078 return 0;
4081 /* Traverse all the service providers we have available */
4082 for( dwIndex=0;
4083 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4084 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4085 ++dwIndex, sizeOfSubKeyName=51 )
4088 HKEY hkServiceProvider;
4089 GUID serviceProviderGUID;
4090 DWORD returnType, sizeOfReturnBuffer = 255;
4091 char returnBuffer[256];
4092 WCHAR buff[51];
4093 DWORD dwTemp, len;
4095 TRACE(" this time through: %s\n", subKeyName );
4097 /* Get a handle for this particular service provider */
4098 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4099 &hkServiceProvider ) != ERROR_SUCCESS )
4101 ERR(": what the heck is going on?\n" );
4102 continue;
4105 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4106 NULL, &returnType, (LPBYTE)returnBuffer,
4107 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4109 ERR(": missing GUID registry data members\n" );
4110 continue;
4113 /* FIXME: Check return types to ensure we're interpreting data right */
4114 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4115 CLSIDFromString( buff, &serviceProviderGUID );
4116 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4118 /* Determine if this is the Service Provider that the user asked for */
4119 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4121 continue;
4124 if( i == 0 ) /* DP SP */
4126 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4127 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4128 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4131 sizeOfReturnBuffer = 255;
4133 /* Get dwReserved1 */
4134 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4135 NULL, &returnType, (LPBYTE)returnBuffer,
4136 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4138 ERR(": missing dwReserved1 registry data members\n") ;
4139 continue;
4142 if( i == 0 )
4143 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4145 sizeOfReturnBuffer = 255;
4147 /* Get dwReserved2 */
4148 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4149 NULL, &returnType, (LPBYTE)returnBuffer,
4150 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4152 ERR(": missing dwReserved1 registry data members\n") ;
4153 continue;
4156 if( i == 0 )
4157 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4159 sizeOfReturnBuffer = 255;
4161 /* Get the path for this service provider */
4162 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4163 NULL, NULL, (LPBYTE)returnBuffer,
4164 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4166 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4167 continue;
4170 TRACE( "Loading %s\n", returnBuffer );
4171 return LoadLibraryA( returnBuffer );
4175 return 0;
4178 static
4179 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4181 HRESULT hr;
4182 LPDPSP_SPINIT SPInit;
4184 /* Initialize the service provider by calling SPInit */
4185 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4187 if( SPInit == NULL )
4189 ERR( "Service provider doesn't provide SPInit interface?\n" );
4190 FreeLibrary( hServiceProvider );
4191 return DPERR_UNAVAILABLE;
4194 TRACE( "Calling SPInit (DP SP entry point)\n" );
4196 hr = (*SPInit)( &This->dp2->spData );
4198 if( FAILED(hr) )
4200 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4201 FreeLibrary( hServiceProvider );
4202 return hr;
4205 /* FIXME: Need to verify the sanity of the returned callback table
4206 * using IsBadCodePtr */
4207 This->dp2->bSPInitialized = TRUE;
4209 /* This interface is now initialized as a DP object */
4210 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4212 /* Store the handle of the module so that we can unload it later */
4213 This->dp2->hServiceProvider = hServiceProvider;
4215 return hr;
4218 static
4219 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4221 HRESULT hr;
4222 LPSP_INIT DPLSPInit;
4224 /* Initialize the service provider by calling SPInit */
4225 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4227 if( DPLSPInit == NULL )
4229 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4230 FreeLibrary( hLobbyProvider );
4231 return DPERR_UNAVAILABLE;
4234 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4236 hr = (*DPLSPInit)( &This->dp2->dplspData );
4238 if( FAILED(hr) )
4240 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4241 FreeLibrary( hLobbyProvider );
4242 return hr;
4245 /* FIXME: Need to verify the sanity of the returned callback table
4246 * using IsBadCodePtr */
4248 This->dp2->bDPLSPInitialized = TRUE;
4250 /* This interface is now initialized as a lobby object */
4251 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4253 /* Store the handle of the module so that we can unload it later */
4254 This->dp2->hDPLobbyProvider = hLobbyProvider;
4256 return hr;
4259 static HRESULT DP_IF_InitializeConnection
4260 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4262 HMODULE hServiceProvider;
4263 HRESULT hr;
4264 GUID guidSP;
4265 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4266 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4268 TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4270 if ( lpConnection == NULL )
4272 return DPERR_INVALIDPARAMS;
4275 if( dwFlags != 0 )
4277 return DPERR_INVALIDFLAGS;
4280 if( This->dp2->connectionInitialized != NO_PROVIDER )
4282 return DPERR_ALREADYINITIALIZED;
4285 /* Find out what the requested SP is and how large this buffer is */
4286 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4287 dwAddrSize, &guidSP );
4289 if( FAILED(hr) )
4291 ERR( "Invalid compound address?\n" );
4292 return DPERR_UNAVAILABLE;
4295 /* Load the service provider */
4296 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4298 if( hServiceProvider == 0 )
4300 ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4301 return DPERR_UNAVAILABLE;
4304 if( bIsDpSp )
4306 /* Fill in what we can of the Service Provider required information.
4307 * The rest was be done in DP_LoadSP
4309 This->dp2->spData.lpAddress = lpConnection;
4310 This->dp2->spData.dwAddressSize = dwAddrSize;
4311 This->dp2->spData.lpGuid = &guidSP;
4313 hr = DP_InitializeDPSP( This, hServiceProvider );
4315 else
4317 This->dp2->dplspData.lpAddress = lpConnection;
4319 hr = DP_InitializeDPLSP( This, hServiceProvider );
4322 if( FAILED(hr) )
4324 return hr;
4327 return DP_OK;
4330 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4331 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4333 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4335 /* This may not be externally invoked once either an SP or LP is initialized */
4336 if( This->dp2->connectionInitialized != NO_PROVIDER )
4338 return DPERR_ALREADYINITIALIZED;
4341 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4344 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4345 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4347 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4349 /* This may not be externally invoked once either an SP or LP is initialized */
4350 if( This->dp2->connectionInitialized != NO_PROVIDER )
4352 return DPERR_ALREADYINITIALIZED;
4355 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4358 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4359 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4360 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4362 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4363 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4366 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4367 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4368 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4370 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4371 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4374 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4375 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4377 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4378 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4379 return DP_OK;
4382 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4383 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4385 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4386 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4387 return DP_OK;
4390 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4391 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4393 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4394 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4395 return DP_OK;
4398 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4399 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4401 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4402 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4403 return DP_OK;
4406 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4407 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4409 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4410 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4411 return DP_OK;
4414 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4415 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4417 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4418 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4419 return DP_OK;
4422 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4423 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4425 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4426 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4427 return DP_OK;
4430 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4431 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4433 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4434 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4435 return DP_OK;
4438 static HRESULT DP_IF_GetGroupParent
4439 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4440 BOOL bAnsi )
4442 lpGroupData lpGData;
4444 TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4446 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4448 return DPERR_INVALIDGROUP;
4451 *lpidGroup = lpGData->dpid;
4453 return DP_OK;
4456 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4457 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4459 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4460 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4462 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4463 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4465 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4466 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4469 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4470 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4472 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4473 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4474 return DP_OK;
4477 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4478 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4480 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4481 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4482 return DP_OK;
4485 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4486 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4488 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4489 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4490 return DP_OK;
4493 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4494 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4496 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4497 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4498 return DP_OK;
4501 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4502 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4504 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4505 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4506 return DP_OK;
4509 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4510 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4512 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4513 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4514 return DP_OK;
4517 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4518 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4520 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4521 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4522 return DP_OK;
4525 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4526 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4528 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4529 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4530 return DP_OK;
4533 static HRESULT DP_SendEx
4534 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4535 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4536 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4538 BOOL bValidDestination = FALSE;
4540 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4541 ": stub\n",
4542 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4543 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4545 if( This->dp2->connectionInitialized == NO_PROVIDER )
4547 return DPERR_UNINITIALIZED;
4550 /* FIXME: Add parameter checking */
4551 /* FIXME: First call to this needs to acquire a message id which will be
4552 * used for multiple sends
4555 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4557 /* Verify that the message is being sent from a valid local player. The
4558 * from player may be anonymous DPID_UNKNOWN
4560 if( idFrom != DPID_UNKNOWN )
4562 if( DP_FindPlayer( This, idFrom ) == NULL )
4564 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4565 return DPERR_INVALIDPLAYER;
4569 /* Verify that the message is being sent to a valid player, group or to
4570 * everyone. If it's valid, send it to those players.
4572 if( idTo == DPID_ALLPLAYERS )
4574 bValidDestination = TRUE;
4576 /* See if SP has the ability to multicast. If so, use it */
4577 if( This->dp2->spData.lpCB->SendToGroupEx )
4579 FIXME( "Use group sendex to group 0\n" );
4581 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4583 FIXME( "Use obsolete group send to group 0\n" );
4585 else /* No multicast, multiplicate */
4587 /* Send to all players we know about */
4588 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4592 if( ( !bValidDestination ) &&
4593 ( DP_FindPlayer( This, idTo ) != NULL )
4596 bValidDestination = TRUE;
4598 /* Have the service provider send this message */
4599 /* FIXME: Could optimize for local interface sends */
4600 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4601 dwTimeout, lpContext, lpdwMsgID );
4604 if( ( !bValidDestination ) &&
4605 ( DP_FindAnyGroup( This, idTo ) != NULL )
4608 bValidDestination = TRUE;
4610 /* See if SP has the ability to multicast. If so, use it */
4611 if( This->dp2->spData.lpCB->SendToGroupEx )
4613 FIXME( "Use group sendex\n" );
4615 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4617 FIXME( "Use obsolete group send to group\n" );
4619 else /* No multicast, multiplicate */
4621 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4624 #if 0
4625 if( bExpectReply )
4627 DWORD dwWaitReturn;
4629 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4631 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4632 if( dwWaitReturn != WAIT_OBJECT_0 )
4634 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4637 #endif
4640 if( !bValidDestination )
4642 return DPERR_INVALIDPLAYER;
4644 else
4646 /* FIXME: Should return what the send returned */
4647 return DP_OK;
4652 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4653 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4654 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4655 LPVOID lpContext, LPDWORD lpdwMsgID )
4657 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4658 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4659 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4662 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4663 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4664 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4665 LPVOID lpContext, LPDWORD lpdwMsgID )
4667 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4668 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4669 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4672 static HRESULT DP_SP_SendEx
4673 ( IDirectPlay2Impl* This, DWORD dwFlags,
4674 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4675 LPVOID lpContext, LPDWORD lpdwMsgID )
4677 LPDPMSG lpMElem;
4679 FIXME( ": stub\n" );
4681 /* FIXME: This queuing should only be for async messages */
4683 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4684 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4686 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4688 /* FIXME: Need to queue based on priority */
4689 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4691 return DP_OK;
4694 static HRESULT DP_IF_GetMessageQueue
4695 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4696 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4698 HRESULT hr = DP_OK;
4700 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4701 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4703 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4704 /* FIXME: What about sends which are not immediate? */
4706 if( This->dp2->spData.lpCB->GetMessageQueue )
4708 DPSP_GETMESSAGEQUEUEDATA data;
4710 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4712 /* FIXME: None of this is documented :( */
4714 data.lpISP = This->dp2->spData.lpISP;
4715 data.dwFlags = dwFlags;
4716 data.idFrom = idFrom;
4717 data.idTo = idTo;
4718 data.lpdwNumMsgs = lpdwNumMsgs;
4719 data.lpdwNumBytes = lpdwNumBytes;
4721 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4723 else
4725 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4728 return hr;
4731 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4732 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4733 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4735 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4736 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4737 lpdwNumBytes, TRUE );
4740 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4741 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4742 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4744 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4745 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4746 lpdwNumBytes, FALSE );
4749 static HRESULT DP_IF_CancelMessage
4750 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4751 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4753 HRESULT hr = DP_OK;
4755 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4756 This, dwMsgID, dwFlags, bAnsi );
4758 if( This->dp2->spData.lpCB->Cancel )
4760 DPSP_CANCELDATA data;
4762 TRACE( "Calling SP Cancel\n" );
4764 /* FIXME: Undocumented callback */
4766 data.lpISP = This->dp2->spData.lpISP;
4767 data.dwFlags = dwFlags;
4768 data.lprglpvSPMsgID = NULL;
4769 data.cSPMsgID = dwMsgID;
4770 data.dwMinPriority = dwMinPriority;
4771 data.dwMaxPriority = dwMaxPriority;
4773 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4775 else
4777 FIXME( "SP doesn't implement Cancel\n" );
4780 return hr;
4783 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4784 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4786 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4788 if( dwFlags != 0 )
4790 return DPERR_INVALIDFLAGS;
4793 if( dwMsgID == 0 )
4795 dwFlags |= DPCANCELSEND_ALL;
4798 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4801 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4802 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4804 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4806 if( dwFlags != 0 )
4808 return DPERR_INVALIDFLAGS;
4811 if( dwMsgID == 0 )
4813 dwFlags |= DPCANCELSEND_ALL;
4816 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4819 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4820 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4821 DWORD dwFlags )
4823 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4825 if( dwFlags != 0 )
4827 return DPERR_INVALIDFLAGS;
4830 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4831 dwMaxPriority, TRUE );
4834 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4835 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4836 DWORD dwFlags )
4838 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4840 if( dwFlags != 0 )
4842 return DPERR_INVALIDFLAGS;
4845 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4846 dwMaxPriority, FALSE );
4849 /* Note: Hack so we can reuse the old functions without compiler warnings */
4850 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4851 # define XCAST(fun) (typeof(directPlay2WVT.fun))
4852 #else
4853 # define XCAST(fun) (void*)
4854 #endif
4856 static const IDirectPlay2Vtbl directPlay2WVT =
4858 XCAST(QueryInterface)DP_QueryInterface,
4859 XCAST(AddRef)DP_AddRef,
4860 XCAST(Release)DP_Release,
4862 DirectPlay2WImpl_AddPlayerToGroup,
4863 DirectPlay2WImpl_Close,
4864 DirectPlay2WImpl_CreateGroup,
4865 DirectPlay2WImpl_CreatePlayer,
4866 DirectPlay2WImpl_DeletePlayerFromGroup,
4867 DirectPlay2WImpl_DestroyGroup,
4868 DirectPlay2WImpl_DestroyPlayer,
4869 DirectPlay2WImpl_EnumGroupPlayers,
4870 DirectPlay2WImpl_EnumGroups,
4871 DirectPlay2WImpl_EnumPlayers,
4872 DirectPlay2WImpl_EnumSessions,
4873 DirectPlay2WImpl_GetCaps,
4874 DirectPlay2WImpl_GetGroupData,
4875 DirectPlay2WImpl_GetGroupName,
4876 DirectPlay2WImpl_GetMessageCount,
4877 DirectPlay2WImpl_GetPlayerAddress,
4878 DirectPlay2WImpl_GetPlayerCaps,
4879 DirectPlay2WImpl_GetPlayerData,
4880 DirectPlay2WImpl_GetPlayerName,
4881 DirectPlay2WImpl_GetSessionDesc,
4882 DirectPlay2WImpl_Initialize,
4883 DirectPlay2WImpl_Open,
4884 DirectPlay2WImpl_Receive,
4885 DirectPlay2WImpl_Send,
4886 DirectPlay2WImpl_SetGroupData,
4887 DirectPlay2WImpl_SetGroupName,
4888 DirectPlay2WImpl_SetPlayerData,
4889 DirectPlay2WImpl_SetPlayerName,
4890 DirectPlay2WImpl_SetSessionDesc
4892 #undef XCAST
4894 /* Note: Hack so we can reuse the old functions without compiler warnings */
4895 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4896 # define XCAST(fun) (typeof(directPlay2AVT.fun))
4897 #else
4898 # define XCAST(fun) (void*)
4899 #endif
4901 static const IDirectPlay2Vtbl directPlay2AVT =
4903 XCAST(QueryInterface)DP_QueryInterface,
4904 XCAST(AddRef)DP_AddRef,
4905 XCAST(Release)DP_Release,
4907 DirectPlay2AImpl_AddPlayerToGroup,
4908 DirectPlay2AImpl_Close,
4909 DirectPlay2AImpl_CreateGroup,
4910 DirectPlay2AImpl_CreatePlayer,
4911 DirectPlay2AImpl_DeletePlayerFromGroup,
4912 DirectPlay2AImpl_DestroyGroup,
4913 DirectPlay2AImpl_DestroyPlayer,
4914 DirectPlay2AImpl_EnumGroupPlayers,
4915 DirectPlay2AImpl_EnumGroups,
4916 DirectPlay2AImpl_EnumPlayers,
4917 DirectPlay2AImpl_EnumSessions,
4918 DirectPlay2AImpl_GetCaps,
4919 DirectPlay2AImpl_GetGroupData,
4920 DirectPlay2AImpl_GetGroupName,
4921 DirectPlay2AImpl_GetMessageCount,
4922 DirectPlay2AImpl_GetPlayerAddress,
4923 DirectPlay2AImpl_GetPlayerCaps,
4924 DirectPlay2AImpl_GetPlayerData,
4925 DirectPlay2AImpl_GetPlayerName,
4926 DirectPlay2AImpl_GetSessionDesc,
4927 DirectPlay2AImpl_Initialize,
4928 DirectPlay2AImpl_Open,
4929 DirectPlay2AImpl_Receive,
4930 DirectPlay2AImpl_Send,
4931 DirectPlay2AImpl_SetGroupData,
4932 DirectPlay2AImpl_SetGroupName,
4933 DirectPlay2AImpl_SetPlayerData,
4934 DirectPlay2AImpl_SetPlayerName,
4935 DirectPlay2AImpl_SetSessionDesc
4937 #undef XCAST
4940 /* Note: Hack so we can reuse the old functions without compiler warnings */
4941 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4942 # define XCAST(fun) (typeof(directPlay3AVT.fun))
4943 #else
4944 # define XCAST(fun) (void*)
4945 #endif
4947 static const IDirectPlay3Vtbl directPlay3AVT =
4949 XCAST(QueryInterface)DP_QueryInterface,
4950 XCAST(AddRef)DP_AddRef,
4951 XCAST(Release)DP_Release,
4953 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
4954 XCAST(Close)DirectPlay2AImpl_Close,
4955 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
4956 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
4957 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
4958 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
4959 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
4960 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
4961 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
4962 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
4963 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
4964 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
4965 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
4966 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
4967 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
4968 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
4969 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
4970 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
4971 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
4972 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
4973 XCAST(Initialize)DirectPlay2AImpl_Initialize,
4974 XCAST(Open)DirectPlay2AImpl_Open,
4975 XCAST(Receive)DirectPlay2AImpl_Receive,
4976 XCAST(Send)DirectPlay2AImpl_Send,
4977 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
4978 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
4979 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
4980 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
4981 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
4983 DirectPlay3AImpl_AddGroupToGroup,
4984 DirectPlay3AImpl_CreateGroupInGroup,
4985 DirectPlay3AImpl_DeleteGroupFromGroup,
4986 DirectPlay3AImpl_EnumConnections,
4987 DirectPlay3AImpl_EnumGroupsInGroup,
4988 DirectPlay3AImpl_GetGroupConnectionSettings,
4989 DirectPlay3AImpl_InitializeConnection,
4990 DirectPlay3AImpl_SecureOpen,
4991 DirectPlay3AImpl_SendChatMessage,
4992 DirectPlay3AImpl_SetGroupConnectionSettings,
4993 DirectPlay3AImpl_StartSession,
4994 DirectPlay3AImpl_GetGroupFlags,
4995 DirectPlay3AImpl_GetGroupParent,
4996 DirectPlay3AImpl_GetPlayerAccount,
4997 DirectPlay3AImpl_GetPlayerFlags
4999 #undef XCAST
5001 /* Note: Hack so we can reuse the old functions without compiler warnings */
5002 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5003 # define XCAST(fun) (typeof(directPlay3WVT.fun))
5004 #else
5005 # define XCAST(fun) (void*)
5006 #endif
5007 static const IDirectPlay3Vtbl directPlay3WVT =
5009 XCAST(QueryInterface)DP_QueryInterface,
5010 XCAST(AddRef)DP_AddRef,
5011 XCAST(Release)DP_Release,
5013 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5014 XCAST(Close)DirectPlay2WImpl_Close,
5015 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5016 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5017 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5018 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5019 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5020 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5021 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5022 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5023 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5024 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5025 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5026 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5027 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5028 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5029 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5030 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5031 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5032 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5033 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5034 XCAST(Open)DirectPlay2WImpl_Open,
5035 XCAST(Receive)DirectPlay2WImpl_Receive,
5036 XCAST(Send)DirectPlay2WImpl_Send,
5037 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5038 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5039 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5040 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5041 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5043 DirectPlay3WImpl_AddGroupToGroup,
5044 DirectPlay3WImpl_CreateGroupInGroup,
5045 DirectPlay3WImpl_DeleteGroupFromGroup,
5046 DirectPlay3WImpl_EnumConnections,
5047 DirectPlay3WImpl_EnumGroupsInGroup,
5048 DirectPlay3WImpl_GetGroupConnectionSettings,
5049 DirectPlay3WImpl_InitializeConnection,
5050 DirectPlay3WImpl_SecureOpen,
5051 DirectPlay3WImpl_SendChatMessage,
5052 DirectPlay3WImpl_SetGroupConnectionSettings,
5053 DirectPlay3WImpl_StartSession,
5054 DirectPlay3WImpl_GetGroupFlags,
5055 DirectPlay3WImpl_GetGroupParent,
5056 DirectPlay3WImpl_GetPlayerAccount,
5057 DirectPlay3WImpl_GetPlayerFlags
5059 #undef XCAST
5061 /* Note: Hack so we can reuse the old functions without compiler warnings */
5062 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5063 # define XCAST(fun) (typeof(directPlay4WVT.fun))
5064 #else
5065 # define XCAST(fun) (void*)
5066 #endif
5067 static const IDirectPlay4Vtbl directPlay4WVT =
5069 XCAST(QueryInterface)DP_QueryInterface,
5070 XCAST(AddRef)DP_AddRef,
5071 XCAST(Release)DP_Release,
5073 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5074 XCAST(Close)DirectPlay2WImpl_Close,
5075 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5076 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5077 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5078 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5079 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5080 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5081 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5082 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5083 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5084 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5085 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5086 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5087 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5088 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5089 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5090 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5091 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5092 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5093 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5094 XCAST(Open)DirectPlay2WImpl_Open,
5095 XCAST(Receive)DirectPlay2WImpl_Receive,
5096 XCAST(Send)DirectPlay2WImpl_Send,
5097 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5098 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5099 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5100 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5101 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5103 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5104 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5105 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5106 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5107 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5108 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5109 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5110 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5111 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5112 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5113 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5114 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5115 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5116 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5117 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5119 DirectPlay4WImpl_GetGroupOwner,
5120 DirectPlay4WImpl_SetGroupOwner,
5121 DirectPlay4WImpl_SendEx,
5122 DirectPlay4WImpl_GetMessageQueue,
5123 DirectPlay4WImpl_CancelMessage,
5124 DirectPlay4WImpl_CancelPriority
5126 #undef XCAST
5129 /* Note: Hack so we can reuse the old functions without compiler warnings */
5130 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5131 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5132 #else
5133 # define XCAST(fun) (void*)
5134 #endif
5135 static const IDirectPlay4Vtbl directPlay4AVT =
5137 XCAST(QueryInterface)DP_QueryInterface,
5138 XCAST(AddRef)DP_AddRef,
5139 XCAST(Release)DP_Release,
5141 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5142 XCAST(Close)DirectPlay2AImpl_Close,
5143 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5144 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5145 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5146 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5147 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5148 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5149 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5150 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5151 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5152 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5153 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5154 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5155 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5156 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5157 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5158 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5159 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5160 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5161 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5162 XCAST(Open)DirectPlay2AImpl_Open,
5163 XCAST(Receive)DirectPlay2AImpl_Receive,
5164 XCAST(Send)DirectPlay2AImpl_Send,
5165 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5166 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5167 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5168 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5169 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5171 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5172 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5173 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5174 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5175 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5176 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5177 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5178 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5179 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5180 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5181 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5182 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5183 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5184 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5185 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5187 DirectPlay4AImpl_GetGroupOwner,
5188 DirectPlay4AImpl_SetGroupOwner,
5189 DirectPlay4AImpl_SendEx,
5190 DirectPlay4AImpl_GetMessageQueue,
5191 DirectPlay4AImpl_CancelMessage,
5192 DirectPlay4AImpl_CancelPriority
5194 #undef XCAST
5196 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5197 DPID idPlayer,
5198 LPVOID* lplpData )
5200 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5202 if( lpPlayer == NULL )
5204 return DPERR_INVALIDPLAYER;
5207 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5209 return DP_OK;
5212 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5213 DPID idPlayer,
5214 LPVOID lpData )
5216 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5218 if( lpPlayer == NULL )
5220 return DPERR_INVALIDPLAYER;
5223 lpPlayer->lpPData->lpSPPlayerData = lpData;
5225 return DP_OK;
5228 /***************************************************************************
5229 * DirectPlayEnumerateAW
5231 * The pointer to the structure lpContext will be filled with the
5232 * appropriate data for each service offered by the OS. These services are
5233 * not necessarily available on this particular machine but are defined
5234 * as simple service providers under the "Service Providers" registry key.
5235 * This structure is then passed to lpEnumCallback for each of the different
5236 * services.
5238 * This API is useful only for applications written using DirectX3 or
5239 * worse. It is superseded by IDirectPlay3::EnumConnections which also
5240 * gives information on the actual connections.
5242 * defn of a service provider:
5243 * A dynamic-link library used by DirectPlay to communicate over a network.
5244 * The service provider contains all the network-specific code required
5245 * to send and receive messages. Online services and network operators can
5246 * supply service providers to use specialized hardware, protocols, communications
5247 * media, and network resources.
5250 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5251 LPDPENUMDPCALLBACKW lpEnumCallbackW,
5252 LPVOID lpContext)
5254 HKEY hkResult;
5255 static const WCHAR searchSubKey[] = {
5256 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5257 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5258 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5259 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5260 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5261 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5263 DWORD dwIndex;
5264 FILETIME filetime;
5266 char *descriptionA = NULL;
5267 DWORD max_sizeOfDescriptionA = 0;
5268 WCHAR *descriptionW = NULL;
5269 DWORD max_sizeOfDescriptionW = 0;
5271 if (!lpEnumCallbackA && !lpEnumCallbackW)
5273 return DPERR_INVALIDPARAMS;
5276 /* Need to loop over the service providers in the registry */
5277 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5278 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5280 /* Hmmm. Does this mean that there are no service providers? */
5281 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5282 return DPERR_GENERIC;
5285 /* Traverse all the service providers we have available */
5286 dwIndex = 0;
5287 while (1)
5289 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5290 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5291 HKEY hkServiceProvider;
5292 GUID serviceProviderGUID;
5293 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5294 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5295 LONG ret_value;
5297 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5298 NULL, NULL, NULL, &filetime);
5299 if (ret_value == ERROR_NO_MORE_ITEMS)
5300 break;
5301 else if (ret_value != ERROR_SUCCESS)
5303 ERR(": could not enumerate on service provider key.\n");
5304 return DPERR_EXCEPTION;
5306 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5308 /* Open the key for this service provider */
5309 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5311 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5312 continue;
5315 /* Get the GUID from the registry */
5316 if (RegQueryValueExW(hkServiceProvider, guidKey,
5317 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5319 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5320 continue;
5322 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5324 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5325 continue;
5327 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5329 /* The enumeration will return FALSE if we are not to continue.
5331 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5332 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5333 * I think that it simply means that they are in-line with DirectX 6.0
5335 if (lpEnumCallbackA)
5337 DWORD sizeOfDescription = 0;
5339 /* Note that this is the A case of this function, so use the A variant to get the description string */
5340 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5341 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5343 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5344 continue;
5346 if (sizeOfDescription > max_sizeOfDescriptionA)
5348 HeapFree(GetProcessHeap(), 0, descriptionA);
5349 max_sizeOfDescriptionA = sizeOfDescription;
5351 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5352 RegQueryValueExA(hkServiceProvider, "DescriptionA",
5353 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5355 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5356 goto end;
5358 else
5360 DWORD sizeOfDescription = 0;
5362 if (RegQueryValueExW(hkServiceProvider, descW,
5363 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5365 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5366 continue;
5368 if (sizeOfDescription > max_sizeOfDescriptionW)
5370 HeapFree(GetProcessHeap(), 0, descriptionW);
5371 max_sizeOfDescriptionW = sizeOfDescription;
5373 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5374 RegQueryValueExW(hkServiceProvider, descW,
5375 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5377 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5378 goto end;
5381 dwIndex++;
5384 end:
5385 HeapFree(GetProcessHeap(), 0, descriptionA);
5386 HeapFree(GetProcessHeap(), 0, descriptionW);
5388 return DP_OK;
5391 /***************************************************************************
5392 * DirectPlayEnumerate [DPLAYX.9]
5393 * DirectPlayEnumerateA [DPLAYX.2]
5395 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5397 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5399 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5402 /***************************************************************************
5403 * DirectPlayEnumerateW [DPLAYX.3]
5405 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5407 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5409 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5412 typedef struct tagCreateEnum
5414 LPVOID lpConn;
5415 LPCGUID lpGuid;
5416 } CreateEnumData, *lpCreateEnumData;
5418 /* Find and copy the matching connection for the SP guid */
5419 static BOOL CALLBACK cbDPCreateEnumConnections(
5420 LPCGUID lpguidSP,
5421 LPVOID lpConnection,
5422 DWORD dwConnectionSize,
5423 LPCDPNAME lpName,
5424 DWORD dwFlags,
5425 LPVOID lpContext)
5427 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5429 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5431 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5433 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5434 dwConnectionSize );
5435 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5437 /* Found the record that we were looking for */
5438 return FALSE;
5441 /* Haven't found what were looking for yet */
5442 return TRUE;
5446 /***************************************************************************
5447 * DirectPlayCreate [DPLAYX.1]
5450 HRESULT WINAPI DirectPlayCreate
5451 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5453 HRESULT hr;
5454 LPDIRECTPLAY3A lpDP3A;
5455 CreateEnumData cbData;
5457 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5459 if( pUnk != NULL )
5461 return CLASS_E_NOAGGREGATION;
5464 if( (lplpDP == NULL) || (lpGUID == NULL) )
5466 return DPERR_INVALIDPARAMS;
5470 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5471 give them an IDirectPlay2A object and hope that doesn't cause problems */
5472 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5474 return DPERR_UNAVAILABLE;
5477 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5479 /* The GUID_NULL means don't bind a service provider. Just return the
5480 interface as is */
5481 return DP_OK;
5484 /* Bind the desired service provider since lpGUID is non NULL */
5485 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5487 /* We're going to use a DP3 interface */
5488 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5489 (LPVOID*)&lpDP3A );
5490 if( FAILED(hr) )
5492 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5493 return hr;
5496 cbData.lpConn = NULL;
5497 cbData.lpGuid = lpGUID;
5499 /* We were given a service provider, find info about it... */
5500 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5501 &cbData, DPCONNECTION_DIRECTPLAY );
5502 if( ( FAILED(hr) ) ||
5503 ( cbData.lpConn == NULL )
5506 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5507 IDirectPlayX_Release( lpDP3A );
5508 return DPERR_UNAVAILABLE;
5511 /* Initialize the service provider */
5512 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5513 if( FAILED(hr) )
5515 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5516 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5517 IDirectPlayX_Release( lpDP3A );
5518 return hr;
5521 /* Release our version of the interface now that we're done with it */
5522 IDirectPlayX_Release( lpDP3A );
5523 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5525 return DP_OK;