winex11: Consider zero-size windows mapped even when they are positioned at 0,0.
[wine/multimedia.git] / dlls / dplayx / dplay.c
blob87eb185bb55914238130d3f42bc9a8fcb9cbd923
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:
651 /* Reply expected */
652 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
653 break;
655 /* Name server needs to handle this request */
656 case DPMSGCMD_ENUMSESSIONSREPLY:
657 /* No reply expected */
658 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
659 This->dp2->spData.dwSPHeaderSize,
660 lpcMessageBody,
661 This->dp2->lpNameServerData );
662 break;
664 case DPMSGCMD_REQUESTNEWPLAYERID:
666 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = lpcMessageBody;
668 LPDPMSG_NEWPLAYERIDREPLY lpReply;
670 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
672 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
674 FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
675 lpcMsg->dwFlags );
677 /* Setup the reply */
678 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
679 This->dp2->spData.dwSPHeaderSize );
681 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
682 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
683 lpReply->envelope.wVersion = DPMSGVER_DP6;
685 lpReply->dpidNewPlayerId = DP_NextObjectId();
687 TRACE( "Allocating new playerid 0x%08x from remote request\n",
688 lpReply->dpidNewPlayerId );
689 break;
692 case DPMSGCMD_GETNAMETABLEREPLY:
693 case DPMSGCMD_NEWPLAYERIDREPLY:
694 #if 0
695 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
696 DebugBreak();
697 #endif
698 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
699 break;
701 #if 1
702 case DPMSGCMD_JUSTENVELOPE:
703 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
704 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
705 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
706 #endif
708 case DPMSGCMD_FORWARDADDPLAYER:
709 #if 0
710 DebugBreak();
711 #endif
712 #if 1
713 TRACE( "Sending message to self to get my addr\n" );
714 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
715 #endif
716 break;
718 case DPMSGCMD_FORWARDADDPLAYERNACK:
719 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
720 break;
722 default:
723 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
724 DebugBreak();
725 break;
728 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
730 return DP_OK;
734 static HRESULT DP_IF_AddPlayerToGroup
735 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
736 DPID idPlayer, BOOL bAnsi )
738 lpGroupData lpGData;
739 lpPlayerList lpPList;
740 lpPlayerList lpNewPList;
742 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
743 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
745 if( This->dp2->connectionInitialized == NO_PROVIDER )
747 return DPERR_UNINITIALIZED;
750 /* Find the group */
751 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
753 return DPERR_INVALIDGROUP;
756 /* Find the player */
757 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
759 return DPERR_INVALIDPLAYER;
762 /* Create a player list (ie "shortcut" ) */
763 lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
764 if( lpNewPList == NULL )
766 return DPERR_CANTADDPLAYER;
769 /* Add the shortcut */
770 lpPList->lpPData->uRef++;
771 lpNewPList->lpPData = lpPList->lpPData;
773 /* Add the player to the list of players for this group */
774 DPQ_INSERT(lpGData->players,lpNewPList,players);
776 /* Let the SP know that we've added a player to the group */
777 if( This->dp2->spData.lpCB->AddPlayerToGroup )
779 DPSP_ADDPLAYERTOGROUPDATA data;
781 TRACE( "Calling SP AddPlayerToGroup\n" );
783 data.idPlayer = idPlayer;
784 data.idGroup = idGroup;
785 data.lpISP = This->dp2->spData.lpISP;
787 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
790 /* Inform all other peers of the addition of player to the group. If there are
791 * no peers keep this event quiet.
792 * Also, if this event was the result of another machine sending it to us,
793 * don't bother rebroadcasting it.
795 if( ( lpMsgHdr == NULL ) &&
796 This->dp2->lpSessionDesc &&
797 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
799 DPMSG_ADDPLAYERTOGROUP msg;
800 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
802 msg.dpIdGroup = idGroup;
803 msg.dpIdPlayer = idPlayer;
805 /* FIXME: Correct to just use send effectively? */
806 /* FIXME: Should size include data w/ message or just message "header" */
807 /* FIXME: Check return code */
808 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
811 return DP_OK;
814 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
815 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
817 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
818 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
821 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
822 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
824 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
825 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
828 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
830 HRESULT hr = DP_OK;
832 TRACE("(%p)->(%u)\n", This, bAnsi );
834 /* FIXME: Need to find a new host I assume (how?) */
835 /* FIXME: Need to destroy all local groups */
836 /* FIXME: Need to migrate all remotely visible players to the new host */
838 /* Invoke the SP callback to inform of session close */
839 if( This->dp2->spData.lpCB->CloseEx )
841 DPSP_CLOSEDATA data;
843 TRACE( "Calling SP CloseEx\n" );
845 data.lpISP = This->dp2->spData.lpISP;
847 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
850 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
852 TRACE( "Calling SP Close (obsolete interface)\n" );
854 hr = (*This->dp2->spData.lpCB->Close)();
857 return hr;
860 static HRESULT WINAPI DirectPlay2AImpl_Close
861 ( LPDIRECTPLAY2A iface )
863 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
864 return DP_IF_Close( This, TRUE );
867 static HRESULT WINAPI DirectPlay2WImpl_Close
868 ( LPDIRECTPLAY2 iface )
870 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
871 return DP_IF_Close( This, FALSE );
874 static
875 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
876 const DPNAME *lpName, DWORD dwFlags,
877 DPID idParent, BOOL bAnsi )
879 lpGroupData lpGData;
881 /* Allocate the new space and add to end of high level group list */
882 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
884 if( lpGData == NULL )
886 return NULL;
889 DPQ_INIT(lpGData->groups);
890 DPQ_INIT(lpGData->players);
892 /* Set the desired player ID - no sanity checking to see if it exists */
893 lpGData->dpid = *lpid;
895 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
897 /* FIXME: Should we check that the parent exists? */
898 lpGData->parent = idParent;
900 /* FIXME: Should we validate the dwFlags? */
901 lpGData->dwFlags = dwFlags;
903 TRACE( "Created group id 0x%08x\n", *lpid );
905 return lpGData;
908 /* This method assumes that all links to it are already deleted */
909 static void
910 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
912 lpGroupList lpGList;
914 TRACE( "(%p)->(0x%08x)\n", This, dpid );
916 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
918 if( lpGList == NULL )
920 ERR( "DPID 0x%08x not found\n", dpid );
921 return;
924 if( --(lpGList->lpGData->uRef) )
926 FIXME( "Why is this not the last reference to group?\n" );
927 DebugBreak();
930 /* Delete player */
931 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
932 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
934 /* Remove and Delete Player List object */
935 HeapFree( GetProcessHeap(), 0, lpGList );
939 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
941 lpGroupList lpGroups;
943 TRACE( "(%p)->(0x%08x)\n", This, dpid );
945 if( dpid == DPID_SYSTEM_GROUP )
947 return This->dp2->lpSysGroup;
949 else
951 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
954 if( lpGroups == NULL )
956 return NULL;
959 return lpGroups->lpGData;
962 static HRESULT DP_IF_CreateGroup
963 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
964 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
965 DWORD dwFlags, BOOL bAnsi )
967 lpGroupData lpGData;
969 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
970 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
971 dwFlags, bAnsi );
973 if( This->dp2->connectionInitialized == NO_PROVIDER )
975 return DPERR_UNINITIALIZED;
978 /* If the name is not specified, we must provide one */
979 if( DPID_UNKNOWN == *lpidGroup )
981 /* If we are the name server, we decide on the group ids. If not, we
982 * must ask for one before attempting a creation.
984 if( This->dp2->bHostInterface )
986 *lpidGroup = DP_NextObjectId();
988 else
990 *lpidGroup = DP_GetRemoteNextObjectId();
994 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
995 DPID_NOPARENT_GROUP, bAnsi );
997 if( lpGData == NULL )
999 return DPERR_CANTADDPLAYER; /* yes player not group */
1002 if( DPID_SYSTEM_GROUP == *lpidGroup )
1004 This->dp2->lpSysGroup = lpGData;
1005 TRACE( "Inserting system group\n" );
1007 else
1009 /* Insert into the system group */
1010 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1011 lpGroup->lpGData = lpGData;
1013 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1016 /* Something is now referencing this data */
1017 lpGData->uRef++;
1019 /* Set all the important stuff for the group */
1020 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1022 /* FIXME: We should only create the system group if GetCaps returns
1023 * DPCAPS_GROUPOPTIMIZED.
1026 /* Let the SP know that we've created this group */
1027 if( This->dp2->spData.lpCB->CreateGroup )
1029 DPSP_CREATEGROUPDATA data;
1030 DWORD dwCreateFlags = 0;
1032 TRACE( "Calling SP CreateGroup\n" );
1034 if( *lpidGroup == DPID_NOPARENT_GROUP )
1035 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1037 if( lpMsgHdr == NULL )
1038 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1040 if( dwFlags & DPGROUP_HIDDEN )
1041 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1043 data.idGroup = *lpidGroup;
1044 data.dwFlags = dwCreateFlags;
1045 data.lpSPMessageHeader = lpMsgHdr;
1046 data.lpISP = This->dp2->spData.lpISP;
1048 (*This->dp2->spData.lpCB->CreateGroup)( &data );
1051 /* Inform all other peers of the creation of a new group. If there are
1052 * no peers keep this event quiet.
1053 * Also if this message was sent to us, don't rebroadcast.
1055 if( ( lpMsgHdr == NULL ) &&
1056 This->dp2->lpSessionDesc &&
1057 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1059 DPMSG_CREATEPLAYERORGROUP msg;
1060 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1062 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
1063 msg.dpId = *lpidGroup;
1064 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1065 msg.lpData = lpData;
1066 msg.dwDataSize = dwDataSize;
1067 msg.dpnName = *lpGroupName;
1068 msg.dpIdParent = DPID_NOPARENT_GROUP;
1069 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1071 /* FIXME: Correct to just use send effectively? */
1072 /* FIXME: Should size include data w/ message or just message "header" */
1073 /* FIXME: Check return code */
1074 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
1075 0, 0, NULL, NULL, bAnsi );
1078 return DP_OK;
1081 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
1082 ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1083 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1085 *lpidGroup = DPID_UNKNOWN;
1087 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1088 lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
1091 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1092 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1093 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1095 *lpidGroup = DPID_UNKNOWN;
1097 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1098 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
1102 static void
1103 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1104 LPVOID lpData, DWORD dwDataSize )
1106 /* Clear out the data with this player */
1107 if( dwFlags & DPSET_LOCAL )
1109 if ( lpGData->dwLocalDataSize != 0 )
1111 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1112 lpGData->lpLocalData = NULL;
1113 lpGData->dwLocalDataSize = 0;
1116 else
1118 if( lpGData->dwRemoteDataSize != 0 )
1120 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1121 lpGData->lpRemoteData = NULL;
1122 lpGData->dwRemoteDataSize = 0;
1126 /* Reallocate for new data */
1127 if( lpData != NULL )
1129 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1130 sizeof( dwDataSize ) );
1131 CopyMemory( lpNewData, lpData, dwDataSize );
1133 if( dwFlags & DPSET_LOCAL )
1135 lpGData->lpLocalData = lpData;
1136 lpGData->dwLocalDataSize = dwDataSize;
1138 else
1140 lpGData->lpRemoteData = lpNewData;
1141 lpGData->dwRemoteDataSize = dwDataSize;
1147 /* This function will just create the storage for the new player. */
1148 static
1149 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1150 LPDPNAME lpName, DWORD dwFlags,
1151 HANDLE hEvent, BOOL bAnsi )
1153 lpPlayerData lpPData;
1155 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1157 /* Allocate the storage for the player and associate it with list element */
1158 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1159 if( lpPData == NULL )
1161 return NULL;
1164 /* Set the desired player ID */
1165 lpPData->dpid = *lpid;
1167 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1169 lpPData->dwFlags = dwFlags;
1171 /* If we were given an event handle, duplicate it */
1172 if( hEvent != 0 )
1174 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1175 GetCurrentProcess(), &lpPData->hEvent,
1176 0, FALSE, DUPLICATE_SAME_ACCESS )
1179 /* FIXME: Memory leak */
1180 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1184 /* Initialize the SP data section */
1185 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1187 TRACE( "Created player id 0x%08x\n", *lpid );
1189 if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1190 This->dp2->lpSessionDesc->dwCurrentPlayers++;
1192 return lpPData;
1195 /* Delete the contents of the DPNAME struct */
1196 static void
1197 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1199 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1200 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1203 /* This method assumes that all links to it are already deleted */
1204 static void
1205 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1207 lpPlayerList lpPList;
1209 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1211 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1213 if( lpPList == NULL )
1215 ERR( "DPID 0x%08x not found\n", dpid );
1216 return;
1219 /* Verify that this is the last reference to the data */
1220 if( --(lpPList->lpPData->uRef) )
1222 FIXME( "Why is this not the last reference to player?\n" );
1223 DebugBreak();
1226 /* Delete player */
1227 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1229 CloseHandle( lpPList->lpPData->hEvent );
1230 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1232 /* Delete Player List object */
1233 HeapFree( GetProcessHeap(), 0, lpPList );
1236 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1238 lpPlayerList lpPlayers;
1240 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1242 if(This->dp2->lpSysGroup == NULL)
1243 return NULL;
1245 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1247 return lpPlayers;
1250 /* Basic area for Dst must already be allocated */
1251 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1253 if( lpSrc == NULL )
1255 ZeroMemory( lpDst, sizeof( *lpDst ) );
1256 lpDst->dwSize = sizeof( *lpDst );
1257 return TRUE;
1260 if( lpSrc->dwSize != sizeof( *lpSrc) )
1262 return FALSE;
1265 /* Delete any existing pointers */
1266 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1267 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1269 /* Copy as required */
1270 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1272 if( bAnsi )
1274 if( lpSrc->u1.lpszShortNameA )
1276 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1277 strlen(lpSrc->u1.lpszShortNameA)+1 );
1278 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1280 if( lpSrc->u2.lpszLongNameA )
1282 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1283 strlen(lpSrc->u2.lpszLongNameA)+1 );
1284 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1287 else
1289 if( lpSrc->u1.lpszShortNameA )
1291 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1292 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1293 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1295 if( lpSrc->u2.lpszLongNameA )
1297 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1298 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1299 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1303 return TRUE;
1306 static void
1307 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1308 LPVOID lpData, DWORD dwDataSize )
1310 /* Clear out the data with this player */
1311 if( dwFlags & DPSET_LOCAL )
1313 if ( lpPData->dwLocalDataSize != 0 )
1315 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1316 lpPData->lpLocalData = NULL;
1317 lpPData->dwLocalDataSize = 0;
1320 else
1322 if( lpPData->dwRemoteDataSize != 0 )
1324 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1325 lpPData->lpRemoteData = NULL;
1326 lpPData->dwRemoteDataSize = 0;
1330 /* Reallocate for new data */
1331 if( lpData != NULL )
1333 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1334 sizeof( dwDataSize ) );
1335 CopyMemory( lpNewData, lpData, dwDataSize );
1337 if( dwFlags & DPSET_LOCAL )
1339 lpPData->lpLocalData = lpData;
1340 lpPData->dwLocalDataSize = dwDataSize;
1342 else
1344 lpPData->lpRemoteData = lpNewData;
1345 lpPData->dwRemoteDataSize = dwDataSize;
1351 static HRESULT DP_IF_CreatePlayer
1352 ( IDirectPlay2Impl* This,
1353 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1354 LPDPID lpidPlayer,
1355 LPDPNAME lpPlayerName,
1356 HANDLE hEvent,
1357 LPVOID lpData,
1358 DWORD dwDataSize,
1359 DWORD dwFlags,
1360 BOOL bAnsi )
1362 HRESULT hr = DP_OK;
1363 lpPlayerData lpPData;
1364 lpPlayerList lpPList;
1365 DWORD dwCreateFlags = 0;
1367 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1368 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1369 dwDataSize, dwFlags, bAnsi );
1370 if( This->dp2->connectionInitialized == NO_PROVIDER )
1372 return DPERR_UNINITIALIZED;
1375 if( dwFlags == 0 )
1377 dwFlags = DPPLAYER_SPECTATOR;
1380 if( lpidPlayer == NULL )
1382 return DPERR_INVALIDPARAMS;
1386 /* Determine the creation flags for the player. These will be passed
1387 * to the name server if requesting a player id and to the SP when
1388 * informing it of the player creation
1391 if( dwFlags & DPPLAYER_SERVERPLAYER )
1393 if( *lpidPlayer == DPID_SERVERPLAYER )
1395 /* Server player for the host interface */
1396 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1398 else if( *lpidPlayer == DPID_NAME_SERVER )
1400 /* Name server - master of everything */
1401 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1403 else
1405 /* Server player for a non host interface */
1406 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1410 if( lpMsgHdr == NULL )
1411 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1414 /* Verify we know how to handle all the flags */
1415 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1416 ( dwFlags & DPPLAYER_SPECTATOR )
1420 /* Assume non fatal failure */
1421 ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1424 /* If the name is not specified, we must provide one */
1425 if( *lpidPlayer == DPID_UNKNOWN )
1427 /* If we are the session master, we dish out the group/player ids */
1428 if( This->dp2->bHostInterface )
1430 *lpidPlayer = DP_NextObjectId();
1432 else
1434 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1436 if( FAILED(hr) )
1438 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1439 return hr;
1443 else
1445 /* FIXME: Would be nice to perhaps verify that we don't already have
1446 * this player.
1450 /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
1451 player total */
1452 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1453 hEvent, bAnsi );
1455 if( lpPData == NULL )
1457 return DPERR_CANTADDPLAYER;
1460 /* Create the list object and link it in */
1461 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1462 if( lpPList == NULL )
1464 FIXME( "Memory leak\n" );
1465 return DPERR_CANTADDPLAYER;
1468 lpPData->uRef = 1;
1469 lpPList->lpPData = lpPData;
1471 /* Add the player to the system group */
1472 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1474 /* Update the information and send it to all players in the session */
1475 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1477 /* Let the SP know that we've created this player */
1478 if( This->dp2->spData.lpCB->CreatePlayer )
1480 DPSP_CREATEPLAYERDATA data;
1482 data.idPlayer = *lpidPlayer;
1483 data.dwFlags = dwCreateFlags;
1484 data.lpSPMessageHeader = lpMsgHdr;
1485 data.lpISP = This->dp2->spData.lpISP;
1487 TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1488 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1490 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1493 if( FAILED(hr) )
1495 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1496 return hr;
1499 /* Now let the SP know that this player is a member of the system group */
1500 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1502 DPSP_ADDPLAYERTOGROUPDATA data;
1504 data.idPlayer = *lpidPlayer;
1505 data.idGroup = DPID_SYSTEM_GROUP;
1506 data.lpISP = This->dp2->spData.lpISP;
1508 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1510 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1513 if( FAILED(hr) )
1515 ERR( "Failed to add player to sys group with sp: %s\n",
1516 DPLAYX_HresultToString(hr) );
1517 return hr;
1520 #if 1
1521 if( This->dp2->bHostInterface == FALSE )
1523 /* Let the name server know about the creation of this player */
1524 /* FIXME: Is this only to be done for the creation of a server player or
1525 * is this used for regular players? If only for server players, move
1526 * this call to DP_SecureOpen(...);
1528 #if 0
1529 TRACE( "Sending message to self to get my addr\n" );
1530 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1531 #endif
1533 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1535 #else
1536 /* Inform all other peers of the creation of a new player. If there are
1537 * no peers keep this quiet.
1538 * Also, if this was a remote event, no need to rebroadcast it.
1540 if( ( lpMsgHdr == NULL ) &&
1541 This->dp2->lpSessionDesc &&
1542 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1544 DPMSG_CREATEPLAYERORGROUP msg;
1545 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1547 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1548 msg.dpId = *lpidPlayer;
1549 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1550 msg.lpData = lpData;
1551 msg.dwDataSize = dwDataSize;
1552 msg.dpnName = *lpPlayerName;
1553 msg.dpIdParent = DPID_NOPARENT_GROUP;
1554 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1556 /* FIXME: Correct to just use send effectively? */
1557 /* FIXME: Should size include data w/ message or just message "header" */
1558 /* FIXME: Check return code */
1559 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1560 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1562 #endif
1564 return hr;
1567 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1568 ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1569 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1571 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1573 if( lpidPlayer == NULL )
1575 return DPERR_INVALIDPARAMS;
1578 if( dwFlags & DPPLAYER_SERVERPLAYER )
1580 *lpidPlayer = DPID_SERVERPLAYER;
1582 else
1584 *lpidPlayer = DPID_UNKNOWN;
1587 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1588 lpData, dwDataSize, dwFlags, TRUE );
1591 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1592 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1593 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1595 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1597 if( lpidPlayer == NULL )
1599 return DPERR_INVALIDPARAMS;
1602 if( dwFlags & DPPLAYER_SERVERPLAYER )
1604 *lpidPlayer = DPID_SERVERPLAYER;
1606 else
1608 *lpidPlayer = DPID_UNKNOWN;
1611 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1612 lpData, dwDataSize, dwFlags, FALSE );
1615 static DPID DP_GetRemoteNextObjectId(void)
1617 FIXME( ":stub\n" );
1619 /* Hack solution */
1620 return DP_NextObjectId();
1623 static HRESULT DP_IF_DeletePlayerFromGroup
1624 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1625 DPID idPlayer, BOOL bAnsi )
1627 HRESULT hr = DP_OK;
1629 lpGroupData lpGData;
1630 lpPlayerList lpPList;
1632 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
1633 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1635 /* Find the group */
1636 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1638 return DPERR_INVALIDGROUP;
1641 /* Find the player */
1642 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1644 return DPERR_INVALIDPLAYER;
1647 /* Remove the player shortcut from the group */
1648 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1650 if( lpPList == NULL )
1652 return DPERR_INVALIDPLAYER;
1655 /* One less reference */
1656 lpPList->lpPData->uRef--;
1658 /* Delete the Player List element */
1659 HeapFree( GetProcessHeap(), 0, lpPList );
1661 /* Inform the SP if they care */
1662 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1664 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1666 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1668 data.idPlayer = idPlayer;
1669 data.idGroup = idGroup;
1670 data.lpISP = This->dp2->spData.lpISP;
1672 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1675 /* Need to send a DELETEPLAYERFROMGROUP message */
1676 FIXME( "Need to send a message\n" );
1678 return hr;
1681 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1682 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1684 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1685 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1688 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1689 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1691 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1692 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1695 typedef struct _DPRGOPContext
1697 IDirectPlay3Impl* This;
1698 BOOL bAnsi;
1699 DPID idGroup;
1700 } DPRGOPContext, *lpDPRGOPContext;
1702 static BOOL CALLBACK
1703 cbRemoveGroupOrPlayer(
1704 DPID dpId,
1705 DWORD dwPlayerType,
1706 LPCDPNAME lpName,
1707 DWORD dwFlags,
1708 LPVOID lpContext )
1710 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1712 TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1713 dpId, dwPlayerType, lpCtxt->idGroup );
1715 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1717 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1718 dpId )
1722 ERR( "Unable to delete group 0x%08x from group 0x%08x\n",
1723 dpId, lpCtxt->idGroup );
1726 else
1728 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1729 NULL, lpCtxt->idGroup,
1730 dpId, lpCtxt->bAnsi )
1734 ERR( "Unable to delete player 0x%08x from grp 0x%08x\n",
1735 dpId, lpCtxt->idGroup );
1739 return TRUE; /* Continue enumeration */
1742 static HRESULT DP_IF_DestroyGroup
1743 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1745 lpGroupData lpGData;
1746 DPRGOPContext context;
1748 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1749 This, lpMsgHdr, idGroup, bAnsi );
1751 /* Find the group */
1752 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1754 return DPERR_INVALIDPLAYER; /* yes player */
1757 context.This = (IDirectPlay3Impl*)This;
1758 context.bAnsi = bAnsi;
1759 context.idGroup = idGroup;
1761 /* Remove all players that this group has */
1762 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1763 cbRemoveGroupOrPlayer, &context, 0, bAnsi );
1765 /* Remove all links to groups that this group has since this is dp3 */
1766 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1767 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1769 /* Remove this group from the parent group - if it has one */
1770 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1771 ( lpGData->parent != DPID_SYSTEM_GROUP )
1774 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1775 idGroup );
1778 /* Now delete this group data and list from the system group */
1779 DP_DeleteGroup( This, idGroup );
1781 /* Let the SP know that we've destroyed this group */
1782 if( This->dp2->spData.lpCB->DeleteGroup )
1784 DPSP_DELETEGROUPDATA data;
1786 FIXME( "data.dwFlags is incorrect\n" );
1788 data.idGroup = idGroup;
1789 data.dwFlags = 0;
1790 data.lpISP = This->dp2->spData.lpISP;
1792 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1795 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1797 return DP_OK;
1800 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1801 ( LPDIRECTPLAY2A iface, DPID idGroup )
1803 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1804 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1807 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1808 ( LPDIRECTPLAY2 iface, DPID idGroup )
1810 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1811 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1814 typedef struct _DPFAGContext
1816 IDirectPlay2Impl* This;
1817 DPID idPlayer;
1818 BOOL bAnsi;
1819 } DPFAGContext, *lpDPFAGContext;
1821 static HRESULT DP_IF_DestroyPlayer
1822 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1824 DPFAGContext cbContext;
1826 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1827 This, lpMsgHdr, idPlayer, bAnsi );
1829 if( This->dp2->connectionInitialized == NO_PROVIDER )
1831 return DPERR_UNINITIALIZED;
1834 if( DP_FindPlayer( This, idPlayer ) == NULL )
1836 return DPERR_INVALIDPLAYER;
1839 /* FIXME: If the player is remote, we must be the host to delete this */
1841 cbContext.This = This;
1842 cbContext.idPlayer = idPlayer;
1843 cbContext.bAnsi = bAnsi;
1845 /* Find each group and call DeletePlayerFromGroup if the player is a
1846 member of the group */
1847 DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
1848 &cbContext, DPENUMGROUPS_ALL, bAnsi );
1850 /* Now delete player and player list from the sys group */
1851 DP_DeletePlayer( This, idPlayer );
1853 /* Let the SP know that we've destroyed this group */
1854 if( This->dp2->spData.lpCB->DeletePlayer )
1856 DPSP_DELETEPLAYERDATA data;
1858 FIXME( "data.dwFlags is incorrect\n" );
1860 data.idPlayer = idPlayer;
1861 data.dwFlags = 0;
1862 data.lpISP = This->dp2->spData.lpISP;
1864 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1867 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1869 return DP_OK;
1872 static BOOL CALLBACK
1873 cbDeletePlayerFromAllGroups(
1874 DPID dpId,
1875 DWORD dwPlayerType,
1876 LPCDPNAME lpName,
1877 DWORD dwFlags,
1878 LPVOID lpContext )
1880 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1882 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1884 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
1885 lpCtxt->bAnsi );
1887 /* Enumerate all groups in this group since this will normally only
1888 * be called for top level groups
1890 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
1891 dpId, NULL,
1892 cbDeletePlayerFromAllGroups,
1893 lpContext, DPENUMGROUPS_ALL,
1894 lpCtxt->bAnsi );
1897 else
1899 ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
1902 return TRUE;
1905 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
1906 ( LPDIRECTPLAY2A iface, DPID idPlayer )
1908 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1909 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1912 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1913 ( LPDIRECTPLAY2 iface, DPID idPlayer )
1915 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1916 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1919 static HRESULT DP_IF_EnumGroupPlayers
1920 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1921 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1922 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1924 lpGroupData lpGData;
1925 lpPlayerList lpPList;
1927 FIXME("(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
1928 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1929 lpContext, dwFlags, bAnsi );
1931 if( This->dp2->connectionInitialized == NO_PROVIDER )
1933 return DPERR_UNINITIALIZED;
1936 /* Find the group */
1937 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1939 return DPERR_INVALIDGROUP;
1942 if( DPQ_IS_EMPTY( lpGData->players ) )
1944 return DP_OK;
1947 lpPList = DPQ_FIRST( lpGData->players );
1949 /* Walk the players in this group */
1950 for( ;; )
1952 /* We do not enum the name server or app server as they are of no
1953 * consequence to the end user.
1955 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
1956 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
1960 /* FIXME: Need to add stuff for dwFlags checking */
1962 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1963 &lpPList->lpPData->name,
1964 lpPList->lpPData->dwFlags,
1965 lpContext )
1968 /* User requested break */
1969 return DP_OK;
1973 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
1975 break;
1978 lpPList = DPQ_NEXT( lpPList->players );
1981 return DP_OK;
1984 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
1985 ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
1986 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1987 LPVOID lpContext, DWORD dwFlags )
1989 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1990 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
1991 lpEnumPlayersCallback2, lpContext,
1992 dwFlags, TRUE );
1995 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
1996 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
1997 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1998 LPVOID lpContext, DWORD dwFlags )
2000 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2001 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2002 lpEnumPlayersCallback2, lpContext,
2003 dwFlags, FALSE );
2006 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2007 static HRESULT DP_IF_EnumGroups
2008 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2009 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2010 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2012 return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2013 DPID_SYSTEM_GROUP, lpguidInstance,
2014 lpEnumPlayersCallback2, lpContext,
2015 dwFlags, bAnsi );
2018 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2019 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2020 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2021 LPVOID lpContext, DWORD dwFlags )
2023 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2024 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2025 lpContext, dwFlags, TRUE );
2028 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2029 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2030 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2031 LPVOID lpContext, DWORD dwFlags )
2033 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2034 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2035 lpContext, dwFlags, FALSE );
2038 static HRESULT DP_IF_EnumPlayers
2039 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2040 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2041 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2043 return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
2044 lpEnumPlayersCallback2, lpContext,
2045 dwFlags, bAnsi );
2048 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2049 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2050 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2051 LPVOID lpContext, DWORD dwFlags )
2053 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2054 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2055 lpContext, dwFlags, TRUE );
2058 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2059 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2060 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2061 LPVOID lpContext, DWORD dwFlags )
2063 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2064 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2065 lpContext, dwFlags, FALSE );
2068 /* This function should call the registered callback function that the user
2069 passed into EnumSessions for each entry available.
2071 static void DP_InvokeEnumSessionCallbacks
2072 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2073 LPVOID lpNSInfo,
2074 DWORD dwTimeout,
2075 LPVOID lpContext )
2077 LPDPSESSIONDESC2 lpSessionDesc;
2079 FIXME( ": not checking for conditions\n" );
2081 /* Not sure if this should be pruning but it's convenient */
2082 NS_PruneSessionCache( lpNSInfo );
2084 NS_ResetSessionEnumeration( lpNSInfo );
2086 /* Enumerate all sessions */
2087 /* FIXME: Need to indicate ANSI */
2088 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2090 TRACE( "EnumSessionsCallback2 invoked\n" );
2091 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2093 return;
2097 /* Invoke one last time to indicate that there is no more to come */
2098 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2101 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2103 EnumSessionAsyncCallbackData* data = lpContext;
2104 HANDLE hSuicideRequest = data->hSuicideRequest;
2105 DWORD dwTimeout = data->dwTimeout;
2107 TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
2109 for( ;; )
2111 HRESULT hr;
2113 /* Sleep up to dwTimeout waiting for request to terminate thread */
2114 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2116 TRACE( "Thread terminating on terminate request\n" );
2117 break;
2120 /* Now resend the enum request */
2121 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2122 data->dwEnumSessionFlags,
2123 data->lpSpData );
2125 if( FAILED(hr) )
2127 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2128 /* FIXME: Should we kill this thread? How to inform the main thread? */
2133 TRACE( "Thread terminating\n" );
2135 /* Clean up the thread data */
2136 CloseHandle( hSuicideRequest );
2137 HeapFree( GetProcessHeap(), 0, lpContext );
2139 /* FIXME: Need to have some notification to main app thread that this is
2140 * dead. It would serve two purposes. 1) allow sync on termination
2141 * so that we don't actually send something to ourselves when we
2142 * become name server (race condition) and 2) so that if we die
2143 * abnormally something else will be able to tell.
2146 return 1;
2149 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
2151 /* Does a thread exist? If so we were doing an async enum session */
2152 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2154 TRACE( "Killing EnumSession thread %p\n",
2155 This->dp2->hEnumSessionThread );
2157 /* Request that the thread kill itself nicely */
2158 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2159 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2161 /* We no longer need to know about the thread */
2162 CloseHandle( This->dp2->hEnumSessionThread );
2164 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2168 static HRESULT DP_IF_EnumSessions
2169 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2170 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2171 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2173 HRESULT hr = DP_OK;
2175 TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x,%u)\n",
2176 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2177 bAnsi );
2178 if( This->dp2->connectionInitialized == NO_PROVIDER )
2180 return DPERR_UNINITIALIZED;
2183 /* Can't enumerate if the interface is already open */
2184 if( This->dp2->bConnectionOpen )
2186 return DPERR_GENERIC;
2189 #if 1
2190 /* The loading of a lobby provider _seems_ to require a backdoor loading
2191 * of the service provider to also associate with this DP object. This is
2192 * because the app doesn't seem to have to call EnumConnections and
2193 * InitializeConnection for the SP before calling this method. As such
2194 * we'll do their dirty work for them with a quick hack so as to always
2195 * load the TCP/IP service provider.
2197 * The correct solution would seem to involve creating a dialog box which
2198 * contains the possible SPs. These dialog boxes most likely follow SDK
2199 * examples.
2201 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2203 LPVOID lpConnection;
2204 DWORD dwSize;
2206 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2208 if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2210 ERR( "Can't build compound addr\n" );
2211 return DPERR_GENERIC;
2214 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2215 0, bAnsi );
2216 if( FAILED(hr) )
2218 return hr;
2221 /* Free up the address buffer */
2222 HeapFree( GetProcessHeap(), 0, lpConnection );
2224 /* The SP is now initialized */
2225 This->dp2->bSPInitialized = TRUE;
2227 #endif
2230 /* Use the service provider default? */
2231 if( dwTimeout == 0 )
2233 DPCAPS spCaps;
2234 spCaps.dwSize = sizeof( spCaps );
2236 DP_IF_GetCaps( This, &spCaps, 0 );
2237 dwTimeout = spCaps.dwTimeout;
2239 /* The service provider doesn't provide one either! */
2240 if( dwTimeout == 0 )
2242 /* Provide the TCP/IP default */
2243 dwTimeout = DPMSG_WAIT_5_SECS;
2247 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2249 DP_KillEnumSessionThread( This );
2250 return hr;
2253 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2255 /* Enumerate everything presently in the local session cache */
2256 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2257 This->dp2->lpNameServerData, dwTimeout,
2258 lpContext );
2260 if( This->dp2->dwEnumSessionLock != 0 )
2261 return DPERR_CONNECTING;
2263 /* See if we've already created a thread to service this interface */
2264 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2266 DWORD dwThreadId;
2267 This->dp2->dwEnumSessionLock++;
2269 /* Send the first enum request inline since the user may cancel a dialog
2270 * if one is presented. Also, may also have a connecting return code.
2272 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2273 dwFlags, &This->dp2->spData );
2275 if( SUCCEEDED(hr) )
2277 EnumSessionAsyncCallbackData* lpData
2278 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2279 /* FIXME: need to kill the thread on object deletion */
2280 lpData->lpSpData = &This->dp2->spData;
2282 lpData->requestGuid = lpsd->guidApplication;
2283 lpData->dwEnumSessionFlags = dwFlags;
2284 lpData->dwTimeout = dwTimeout;
2286 This->dp2->hKillEnumSessionThreadEvent =
2287 CreateEventW( NULL, TRUE, FALSE, NULL );
2289 if( !DuplicateHandle( GetCurrentProcess(),
2290 This->dp2->hKillEnumSessionThreadEvent,
2291 GetCurrentProcess(),
2292 &lpData->hSuicideRequest,
2293 0, FALSE, DUPLICATE_SAME_ACCESS )
2296 ERR( "Can't duplicate thread killing handle\n" );
2299 TRACE( ": creating EnumSessionsRequest thread\n" );
2301 This->dp2->hEnumSessionThread = CreateThread( NULL,
2303 DP_EnumSessionsSendAsyncRequestThread,
2304 lpData,
2306 &dwThreadId );
2308 This->dp2->dwEnumSessionLock--;
2311 else
2313 /* Invalidate the session cache for the interface */
2314 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2316 /* Send the broadcast for session enumeration */
2317 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2318 dwFlags,
2319 &This->dp2->spData );
2322 SleepEx( dwTimeout, FALSE );
2324 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2325 This->dp2->lpNameServerData, dwTimeout,
2326 lpContext );
2329 return hr;
2332 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2333 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2334 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2335 LPVOID lpContext, DWORD dwFlags )
2337 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2338 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2339 lpContext, dwFlags, TRUE );
2342 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2343 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2344 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2345 LPVOID lpContext, DWORD dwFlags )
2347 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2348 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2349 lpContext, dwFlags, FALSE );
2352 static HRESULT DP_IF_GetPlayerCaps
2353 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2354 DWORD dwFlags )
2356 DPSP_GETCAPSDATA data;
2358 TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
2360 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2362 return DPERR_UNINITIALIZED;
2365 /* Query the service provider */
2366 data.idPlayer = idPlayer;
2367 data.dwFlags = dwFlags;
2368 data.lpCaps = lpDPCaps;
2369 data.lpISP = This->dp2->spData.lpISP;
2371 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2374 static HRESULT DP_IF_GetCaps
2375 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2377 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2380 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2381 ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2383 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2384 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2387 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2388 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2390 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2391 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2394 static HRESULT DP_IF_GetGroupData
2395 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2396 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2398 lpGroupData lpGData;
2399 DWORD dwRequiredBufferSize;
2400 LPVOID lpCopyDataFrom;
2402 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2403 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2405 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2407 return DPERR_INVALIDGROUP;
2410 /* How much buffer is required? */
2411 if( dwFlags & DPSET_LOCAL )
2413 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2414 lpCopyDataFrom = lpGData->lpLocalData;
2416 else
2418 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2419 lpCopyDataFrom = lpGData->lpRemoteData;
2422 /* Is the user requesting to know how big a buffer is required? */
2423 if( ( lpData == NULL ) ||
2424 ( *lpdwDataSize < dwRequiredBufferSize )
2427 *lpdwDataSize = dwRequiredBufferSize;
2428 return DPERR_BUFFERTOOSMALL;
2431 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2433 return DP_OK;
2436 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2437 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2438 LPDWORD lpdwDataSize, DWORD dwFlags )
2440 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2441 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2442 dwFlags, TRUE );
2445 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2446 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2447 LPDWORD lpdwDataSize, DWORD dwFlags )
2449 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2450 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2451 dwFlags, FALSE );
2454 static HRESULT DP_IF_GetGroupName
2455 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2456 LPDWORD lpdwDataSize, BOOL bAnsi )
2458 lpGroupData lpGData;
2459 LPDPNAME lpName = lpData;
2460 DWORD dwRequiredDataSize;
2462 FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2463 This, idGroup, lpData, lpdwDataSize, bAnsi );
2465 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2467 return DPERR_INVALIDGROUP;
2470 dwRequiredDataSize = lpGData->name.dwSize;
2472 if( lpGData->name.u1.lpszShortNameA )
2474 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2477 if( lpGData->name.u2.lpszLongNameA )
2479 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2482 if( ( lpData == NULL ) ||
2483 ( *lpdwDataSize < dwRequiredDataSize )
2486 *lpdwDataSize = dwRequiredDataSize;
2487 return DPERR_BUFFERTOOSMALL;
2490 /* Copy the structure */
2491 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2493 if( lpGData->name.u1.lpszShortNameA )
2495 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2496 lpGData->name.u1.lpszShortNameA );
2498 else
2500 lpName->u1.lpszShortNameA = NULL;
2503 if( lpGData->name.u1.lpszShortNameA )
2505 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2506 lpGData->name.u2.lpszLongNameA );
2508 else
2510 lpName->u2.lpszLongNameA = NULL;
2513 return DP_OK;
2516 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2517 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2518 LPDWORD lpdwDataSize )
2520 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2521 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2524 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2525 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2526 LPDWORD lpdwDataSize )
2528 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2529 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2532 static HRESULT DP_IF_GetMessageCount
2533 ( IDirectPlay2Impl* This, DPID idPlayer,
2534 LPDWORD lpdwCount, BOOL bAnsi )
2536 FIXME("(%p)->(0x%08x,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2537 return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2538 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2539 bAnsi );
2542 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2543 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2545 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2546 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2549 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2550 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2552 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2553 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2556 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2557 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2559 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2560 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2561 return DP_OK;
2564 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2565 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2567 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2568 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2569 return DP_OK;
2572 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2573 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2574 DWORD dwFlags )
2576 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2577 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2580 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2581 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2582 DWORD dwFlags )
2584 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2585 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2588 static HRESULT DP_IF_GetPlayerData
2589 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2590 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2592 lpPlayerList lpPList;
2593 DWORD dwRequiredBufferSize;
2594 LPVOID lpCopyDataFrom;
2596 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2597 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2599 if( This->dp2->connectionInitialized == NO_PROVIDER )
2601 return DPERR_UNINITIALIZED;
2604 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2606 return DPERR_INVALIDPLAYER;
2609 /* How much buffer is required? */
2610 if( dwFlags & DPSET_LOCAL )
2612 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2613 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2615 else
2617 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2618 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2621 /* Is the user requesting to know how big a buffer is required? */
2622 if( ( lpData == NULL ) ||
2623 ( *lpdwDataSize < dwRequiredBufferSize )
2626 *lpdwDataSize = dwRequiredBufferSize;
2627 return DPERR_BUFFERTOOSMALL;
2630 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2632 return DP_OK;
2635 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2636 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2637 LPDWORD lpdwDataSize, DWORD dwFlags )
2639 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2640 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2641 dwFlags, TRUE );
2644 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2645 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2646 LPDWORD lpdwDataSize, DWORD dwFlags )
2648 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2649 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2650 dwFlags, FALSE );
2653 static HRESULT DP_IF_GetPlayerName
2654 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2655 LPDWORD lpdwDataSize, BOOL bAnsi )
2657 lpPlayerList lpPList;
2658 LPDPNAME lpName = lpData;
2659 DWORD dwRequiredDataSize;
2661 FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2662 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2664 if( This->dp2->connectionInitialized == NO_PROVIDER )
2666 return DPERR_UNINITIALIZED;
2669 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2671 return DPERR_INVALIDPLAYER;
2674 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2676 if( lpPList->lpPData->name.u1.lpszShortNameA )
2678 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2681 if( lpPList->lpPData->name.u2.lpszLongNameA )
2683 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2686 if( ( lpData == NULL ) ||
2687 ( *lpdwDataSize < dwRequiredDataSize )
2690 *lpdwDataSize = dwRequiredDataSize;
2691 return DPERR_BUFFERTOOSMALL;
2694 /* Copy the structure */
2695 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2697 if( lpPList->lpPData->name.u1.lpszShortNameA )
2699 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2700 lpPList->lpPData->name.u1.lpszShortNameA );
2702 else
2704 lpName->u1.lpszShortNameA = NULL;
2707 if( lpPList->lpPData->name.u1.lpszShortNameA )
2709 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2710 lpPList->lpPData->name.u2.lpszLongNameA );
2712 else
2714 lpName->u2.lpszLongNameA = NULL;
2717 return DP_OK;
2720 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2721 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2722 LPDWORD lpdwDataSize )
2724 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2725 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2728 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2729 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2730 LPDWORD lpdwDataSize )
2732 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2733 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2736 static HRESULT DP_GetSessionDesc
2737 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2738 BOOL bAnsi )
2740 DWORD dwRequiredSize;
2742 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2744 if( This->dp2->connectionInitialized == NO_PROVIDER )
2746 return DPERR_UNINITIALIZED;
2749 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2751 return DPERR_INVALIDPARAMS;
2754 /* FIXME: Get from This->dp2->lpSessionDesc */
2755 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2757 if ( ( lpData == NULL ) ||
2758 ( *lpdwDataSize < dwRequiredSize )
2761 *lpdwDataSize = dwRequiredSize;
2762 return DPERR_BUFFERTOOSMALL;
2765 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2767 return DP_OK;
2770 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2771 ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2773 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2774 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2777 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2778 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2780 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2781 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2784 /* Intended only for COM compatibility. Always returns an error. */
2785 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2786 ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2788 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2789 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2790 return DPERR_ALREADYINITIALIZED;
2793 /* Intended only for COM compatibility. Always returns an error. */
2794 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2795 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2797 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2798 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2799 return DPERR_ALREADYINITIALIZED;
2803 static HRESULT DP_SecureOpen
2804 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2805 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2806 BOOL bAnsi )
2808 HRESULT hr = DP_OK;
2810 FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2811 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2813 if( This->dp2->connectionInitialized == NO_PROVIDER )
2815 return DPERR_UNINITIALIZED;
2818 if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
2820 TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
2821 return DPERR_INVALIDPARAMS;
2824 if( This->dp2->bConnectionOpen )
2826 TRACE( ": rejecting already open connection.\n" );
2827 return DPERR_ALREADYINITIALIZED;
2830 /* If we're enumerating, kill the thread */
2831 DP_KillEnumSessionThread( This );
2833 if( dwFlags & DPOPEN_CREATE )
2835 /* Rightoo - this computer is the host and the local computer needs to be
2836 the name server so that others can join this session */
2837 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2839 This->dp2->bHostInterface = TRUE;
2841 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2842 if( FAILED( hr ) )
2844 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2845 return hr;
2849 /* Invoke the conditional callback for the service provider */
2850 if( This->dp2->spData.lpCB->Open )
2852 DPSP_OPENDATA data;
2854 FIXME( "Not all data fields are correct. Need new parameter\n" );
2856 data.bCreate = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
2857 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2858 : NS_GetNSAddr( This->dp2->lpNameServerData );
2859 data.lpISP = This->dp2->spData.lpISP;
2860 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
2861 data.dwOpenFlags = dwFlags;
2862 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2864 hr = (*This->dp2->spData.lpCB->Open)(&data);
2865 if( FAILED( hr ) )
2867 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2868 return hr;
2873 /* Create the system group of which everything is a part of */
2874 DPID systemGroup = DPID_SYSTEM_GROUP;
2876 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2877 NULL, 0, 0, TRUE );
2881 if( dwFlags & DPOPEN_JOIN )
2883 DPID dpidServerId = DPID_UNKNOWN;
2885 /* Create the server player for this interface. This way we can receive
2886 * messages for this session.
2888 /* FIXME: I suppose that we should be setting an event for a receive
2889 * type of thing. That way the messaging thread could know to wake
2890 * up. DPlay would then trigger the hEvent for the player the
2891 * message is directed to.
2893 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2895 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2898 else if( dwFlags & DPOPEN_CREATE )
2900 DPID dpidNameServerId = DPID_NAME_SERVER;
2902 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2903 0, DPPLAYER_SERVERPLAYER, bAnsi );
2906 if( FAILED(hr) )
2908 ERR( "Couldn't create name server/system player: %s\n",
2909 DPLAYX_HresultToString(hr) );
2912 return hr;
2915 static HRESULT WINAPI DirectPlay2AImpl_Open
2916 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2918 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2919 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2920 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
2923 static HRESULT WINAPI DirectPlay2WImpl_Open
2924 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2926 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2927 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2928 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
2931 static HRESULT DP_IF_Receive
2932 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2933 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2935 LPDPMSG lpMsg = NULL;
2937 FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
2938 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2940 if( This->dp2->connectionInitialized == NO_PROVIDER )
2942 return DPERR_UNINITIALIZED;
2945 if( dwFlags == 0 )
2947 dwFlags = DPRECEIVE_ALL;
2950 /* If the lpData is NULL, we must be peeking the message */
2951 if( ( lpData == NULL ) &&
2952 !( dwFlags & DPRECEIVE_PEEK )
2955 return DPERR_INVALIDPARAMS;
2958 if( dwFlags & DPRECEIVE_ALL )
2960 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2962 if( !( dwFlags & DPRECEIVE_PEEK ) )
2964 FIXME( "Remove from queue\n" );
2967 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2968 ( dwFlags & DPRECEIVE_FROMPLAYER )
2971 FIXME( "Find matching message 0x%08x\n", dwFlags );
2973 else
2975 ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
2978 if( lpMsg == NULL )
2980 return DPERR_NOMESSAGES;
2983 /* Copy into the provided buffer */
2984 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
2986 return DP_OK;
2989 static HRESULT WINAPI DirectPlay2AImpl_Receive
2990 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
2991 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2993 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2994 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2995 lpData, lpdwDataSize, TRUE );
2998 static HRESULT WINAPI DirectPlay2WImpl_Receive
2999 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
3000 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3002 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3003 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3004 lpData, lpdwDataSize, FALSE );
3007 static HRESULT WINAPI DirectPlay2AImpl_Send
3008 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3010 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3011 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3012 0, 0, NULL, NULL, TRUE );
3015 static HRESULT WINAPI DirectPlay2WImpl_Send
3016 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3018 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3019 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3020 0, 0, NULL, NULL, FALSE );
3023 static HRESULT DP_IF_SetGroupData
3024 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3025 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3027 lpGroupData lpGData;
3029 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3030 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3032 /* Parameter check */
3033 if( ( lpData == NULL ) &&
3034 ( dwDataSize != 0 )
3037 return DPERR_INVALIDPARAMS;
3040 /* Find the pointer to the data for this player */
3041 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3043 return DPERR_INVALIDOBJECT;
3046 if( !(dwFlags & DPSET_LOCAL) )
3048 FIXME( "Was this group created by this interface?\n" );
3049 /* FIXME: If this is a remote update need to allow it but not
3050 * send a message.
3054 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3056 /* FIXME: Only send a message if this group is local to the session otherwise
3057 * it will have been rejected above
3059 if( !(dwFlags & DPSET_LOCAL) )
3061 FIXME( "Send msg?\n" );
3064 return DP_OK;
3067 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3068 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3069 DWORD dwDataSize, DWORD dwFlags )
3071 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3072 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3075 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3076 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3077 DWORD dwDataSize, DWORD dwFlags )
3079 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3080 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3083 static HRESULT DP_IF_SetGroupName
3084 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3085 DWORD dwFlags, BOOL bAnsi )
3087 lpGroupData lpGData;
3089 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3090 lpGroupName, dwFlags, bAnsi );
3092 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3094 return DPERR_INVALIDGROUP;
3097 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3099 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3100 FIXME( "Message not sent and dwFlags ignored\n" );
3102 return DP_OK;
3105 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3106 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3107 DWORD dwFlags )
3109 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3110 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3113 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3114 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3115 DWORD dwFlags )
3117 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3118 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3121 static HRESULT DP_IF_SetPlayerData
3122 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3123 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3125 lpPlayerList lpPList;
3127 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3128 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3130 if( This->dp2->connectionInitialized == NO_PROVIDER )
3132 return DPERR_UNINITIALIZED;
3135 /* Parameter check */
3136 if( ( lpData == NULL ) &&
3137 ( dwDataSize != 0 )
3140 return DPERR_INVALIDPARAMS;
3143 /* Find the pointer to the data for this player */
3144 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3146 return DPERR_INVALIDPLAYER;
3149 if( !(dwFlags & DPSET_LOCAL) )
3151 FIXME( "Was this group created by this interface?\n" );
3152 /* FIXME: If this is a remote update need to allow it but not
3153 * send a message.
3157 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3159 if( !(dwFlags & DPSET_LOCAL) )
3161 FIXME( "Send msg?\n" );
3164 return DP_OK;
3167 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3168 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3169 DWORD dwDataSize, DWORD dwFlags )
3171 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3172 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3173 dwFlags, TRUE );
3176 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3177 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3178 DWORD dwDataSize, DWORD dwFlags )
3180 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3181 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3182 dwFlags, FALSE );
3185 static HRESULT DP_IF_SetPlayerName
3186 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3187 DWORD dwFlags, BOOL bAnsi )
3189 lpPlayerList lpPList;
3191 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3192 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3194 if( This->dp2->connectionInitialized == NO_PROVIDER )
3196 return DPERR_UNINITIALIZED;
3199 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3201 return DPERR_INVALIDGROUP;
3204 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3206 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3207 FIXME( "Message not sent and dwFlags ignored\n" );
3209 return DP_OK;
3212 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3213 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3214 DWORD dwFlags )
3216 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3217 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3220 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3221 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3222 DWORD dwFlags )
3224 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3225 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3228 static HRESULT DP_SetSessionDesc
3229 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3230 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3232 DWORD dwRequiredSize;
3233 LPDPSESSIONDESC2 lpTempSessDesc;
3235 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3236 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3238 if( This->dp2->connectionInitialized == NO_PROVIDER )
3240 return DPERR_UNINITIALIZED;
3243 if( dwFlags )
3245 return DPERR_INVALIDPARAMS;
3248 /* Only the host is allowed to update the session desc */
3249 if( !This->dp2->bHostInterface )
3251 return DPERR_ACCESSDENIED;
3254 /* FIXME: Copy into This->dp2->lpSessionDesc */
3255 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3256 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3258 if( lpTempSessDesc == NULL )
3260 return DPERR_OUTOFMEMORY;
3263 /* Free the old */
3264 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3266 This->dp2->lpSessionDesc = lpTempSessDesc;
3267 /* Set the new */
3268 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3269 if( bInitial )
3271 /*Initializing session GUID*/
3272 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3274 /* If this is an external invocation of the interface, we should be
3275 * letting everyone know that things have changed. Otherwise this is
3276 * just an initialization and it doesn't need to be propagated.
3278 if( !bInitial )
3280 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3283 return DP_OK;
3286 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3287 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3289 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3290 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3293 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3294 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3296 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3297 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3300 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3301 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3303 DWORD dwSize = 0;
3305 if( lpSessDesc == NULL )
3307 /* Hmmm..don't need any size? */
3308 ERR( "NULL lpSessDesc\n" );
3309 return dwSize;
3312 dwSize += sizeof( *lpSessDesc );
3314 if( bAnsi )
3316 if( lpSessDesc->u1.lpszSessionNameA )
3318 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3321 if( lpSessDesc->u2.lpszPasswordA )
3323 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3326 else /* UNICODE */
3328 if( lpSessDesc->u1.lpszSessionName )
3330 dwSize += sizeof( WCHAR ) *
3331 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3334 if( lpSessDesc->u2.lpszPassword )
3336 dwSize += sizeof( WCHAR ) *
3337 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3341 return dwSize;
3344 /* Assumes that contiguous buffers are already allocated. */
3345 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3346 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3348 BYTE* lpStartOfFreeSpace;
3350 if( lpSessionDest == NULL )
3352 ERR( "NULL lpSessionDest\n" );
3353 return;
3356 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3358 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3360 if( bAnsi )
3362 if( lpSessionSrc->u1.lpszSessionNameA )
3364 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3365 lpSessionDest->u1.lpszSessionNameA );
3366 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3367 lpStartOfFreeSpace +=
3368 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3371 if( lpSessionSrc->u2.lpszPasswordA )
3373 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3374 lpSessionDest->u2.lpszPasswordA );
3375 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3378 else /* UNICODE */
3380 if( lpSessionSrc->u1.lpszSessionName )
3382 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3383 lpSessionDest->u1.lpszSessionName );
3384 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3385 lpStartOfFreeSpace += sizeof(WCHAR) *
3386 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3389 if( lpSessionSrc->u2.lpszPassword )
3391 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3392 lpSessionDest->u2.lpszPassword );
3393 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3399 static HRESULT DP_IF_AddGroupToGroup
3400 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3402 lpGroupData lpGData;
3403 lpGroupList lpNewGList;
3405 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3407 if( This->dp2->connectionInitialized == NO_PROVIDER )
3409 return DPERR_UNINITIALIZED;
3412 if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3414 return DPERR_INVALIDGROUP;
3417 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3419 return DPERR_INVALIDGROUP;
3422 /* Create a player list (ie "shortcut" ) */
3423 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3424 if( lpNewGList == NULL )
3426 return DPERR_CANTADDPLAYER;
3429 /* Add the shortcut */
3430 lpGData->uRef++;
3431 lpNewGList->lpGData = lpGData;
3433 /* Add the player to the list of players for this group */
3434 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3436 /* Send a ADDGROUPTOGROUP message */
3437 FIXME( "Not sending message\n" );
3439 return DP_OK;
3442 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3443 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3445 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3446 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3449 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3450 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3452 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3453 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3456 static HRESULT DP_IF_CreateGroupInGroup
3457 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3458 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3459 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3461 lpGroupData lpGParentData;
3462 lpGroupList lpGList;
3463 lpGroupData lpGData;
3465 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3466 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3467 dwDataSize, dwFlags, bAnsi );
3469 if( This->dp2->connectionInitialized == NO_PROVIDER )
3471 return DPERR_UNINITIALIZED;
3474 /* Verify that the specified parent is valid */
3475 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3476 idParentGroup ) ) == NULL
3479 return DPERR_INVALIDGROUP;
3482 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3483 dwFlags, idParentGroup, bAnsi );
3485 if( lpGData == NULL )
3487 return DPERR_CANTADDPLAYER; /* yes player not group */
3490 /* Something else is referencing this data */
3491 lpGData->uRef++;
3493 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3495 /* The list has now been inserted into the interface group list. We now
3496 need to put a "shortcut" to this group in the parent group */
3497 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3498 if( lpGList == NULL )
3500 FIXME( "Memory leak\n" );
3501 return DPERR_CANTADDPLAYER; /* yes player not group */
3504 lpGList->lpGData = lpGData;
3506 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3508 /* Let the SP know that we've created this group */
3509 if( This->dp2->spData.lpCB->CreateGroup )
3511 DPSP_CREATEGROUPDATA data;
3513 TRACE( "Calling SP CreateGroup\n" );
3515 data.idGroup = *lpidGroup;
3516 data.dwFlags = dwFlags;
3517 data.lpSPMessageHeader = lpMsgHdr;
3518 data.lpISP = This->dp2->spData.lpISP;
3520 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3523 /* Inform all other peers of the creation of a new group. If there are
3524 * no peers keep this quiet.
3526 if( This->dp2->lpSessionDesc &&
3527 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3529 DPMSG_CREATEPLAYERORGROUP msg;
3531 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3532 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3533 msg.dpId = *lpidGroup;
3534 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3535 msg.lpData = lpData;
3536 msg.dwDataSize = dwDataSize;
3537 msg.dpnName = *lpGroupName;
3539 /* FIXME: Correct to just use send effectively? */
3540 /* FIXME: Should size include data w/ message or just message "header" */
3541 /* FIXME: Check return code */
3542 DP_SendEx( (IDirectPlay2Impl*)This,
3543 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3544 0, 0, NULL, NULL, bAnsi );
3547 return DP_OK;
3550 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3551 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3552 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3553 DWORD dwFlags )
3555 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3557 *lpidGroup = DPID_UNKNOWN;
3559 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3560 lpGroupName, lpData, dwDataSize, dwFlags,
3561 TRUE );
3564 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3565 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3566 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3567 DWORD dwFlags )
3569 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3571 *lpidGroup = DPID_UNKNOWN;
3573 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3574 lpGroupName, lpData, dwDataSize,
3575 dwFlags, FALSE );
3578 static HRESULT DP_IF_DeleteGroupFromGroup
3579 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3581 lpGroupList lpGList;
3582 lpGroupData lpGParentData;
3584 TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3586 /* Is the parent group valid? */
3587 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3589 return DPERR_INVALIDGROUP;
3592 /* Remove the group from the parent group queue */
3593 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3595 if( lpGList == NULL )
3597 return DPERR_INVALIDGROUP;
3600 /* Decrement the ref count */
3601 lpGList->lpGData->uRef--;
3603 /* Free up the list item */
3604 HeapFree( GetProcessHeap(), 0, lpGList );
3606 /* Should send a DELETEGROUPFROMGROUP message */
3607 FIXME( "message not sent\n" );
3609 return DP_OK;
3612 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3613 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3615 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3616 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3619 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3620 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3622 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3623 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3626 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3627 LPDWORD lpdwBufSize )
3629 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3630 HRESULT hr;
3632 dpCompoundAddress.dwDataSize = sizeof( GUID );
3633 dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3634 dpCompoundAddress.lpData = lpcSpGuid;
3636 *lplpAddrBuf = NULL;
3637 *lpdwBufSize = 0;
3639 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3640 lpdwBufSize, TRUE );
3642 if( hr != DPERR_BUFFERTOOSMALL )
3644 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3645 return FALSE;
3648 /* Now allocate the buffer */
3649 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3650 *lpdwBufSize );
3652 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3653 lpdwBufSize, TRUE );
3654 if( FAILED(hr) )
3656 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3657 return FALSE;
3660 return TRUE;
3663 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
3664 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3666 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3667 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3669 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3670 if( dwFlags == 0 )
3672 dwFlags = DPCONNECTION_DIRECTPLAY;
3675 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3676 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3679 return DPERR_INVALIDFLAGS;
3682 if( !lpEnumCallback )
3684 return DPERR_INVALIDPARAMS;
3687 /* Enumerate DirectPlay service providers */
3688 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3690 HKEY hkResult;
3691 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3692 LPCSTR guidDataSubKey = "Guid";
3693 char subKeyName[51];
3694 DWORD dwIndex, sizeOfSubKeyName=50;
3695 FILETIME filetime;
3697 /* Need to loop over the service providers in the registry */
3698 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3699 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3701 /* Hmmm. Does this mean that there are no service providers? */
3702 ERR(": no service providers?\n");
3703 return DP_OK;
3707 /* Traverse all the service providers we have available */
3708 for( dwIndex=0;
3709 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3710 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3711 ++dwIndex, sizeOfSubKeyName=51 )
3714 HKEY hkServiceProvider;
3715 GUID serviceProviderGUID;
3716 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3717 char returnBuffer[51];
3718 WCHAR buff[51];
3719 DPNAME dpName;
3720 BOOL bBuildPass;
3722 LPVOID lpAddressBuffer = NULL;
3723 DWORD dwAddressBufferSize = 0;
3725 TRACE(" this time through: %s\n", subKeyName );
3727 /* Get a handle for this particular service provider */
3728 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3729 &hkServiceProvider ) != ERROR_SUCCESS )
3731 ERR(": what the heck is going on?\n" );
3732 continue;
3735 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3736 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3737 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3739 ERR(": missing GUID registry data members\n" );
3740 RegCloseKey(hkServiceProvider);
3741 continue;
3743 RegCloseKey(hkServiceProvider);
3745 /* FIXME: Check return types to ensure we're interpreting data right */
3746 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3747 CLSIDFromString( buff, &serviceProviderGUID );
3748 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3750 /* Fill in the DPNAME struct for the service provider */
3751 dpName.dwSize = sizeof( dpName );
3752 dpName.dwFlags = 0;
3753 dpName.u1.lpszShortNameA = subKeyName;
3754 dpName.u2.lpszLongNameA = NULL;
3756 /* Create the compound address for the service provider.
3757 * NOTE: This is a gruesome architectural scar right now. DP
3758 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3759 * native dll just gets around this little bit by allocating an
3760 * 80 byte buffer which isn't even filled with a valid compound
3761 * address. Oh well. Creating a proper compound address is the
3762 * way to go anyways despite this method taking slightly more
3763 * heap space and realtime :) */
3765 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3766 &lpAddressBuffer,
3767 &dwAddressBufferSize );
3768 if( !bBuildPass )
3770 ERR( "Can't build compound addr\n" );
3771 return DPERR_GENERIC;
3774 /* The enumeration will return FALSE if we are not to continue */
3775 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3776 &dpName, dwFlags, lpContext ) )
3778 return DP_OK;
3783 /* Enumerate DirectPlayLobby service providers */
3784 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3786 HKEY hkResult;
3787 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3788 LPCSTR guidDataSubKey = "Guid";
3789 char subKeyName[51];
3790 DWORD dwIndex, sizeOfSubKeyName=50;
3791 FILETIME filetime;
3793 /* Need to loop over the service providers in the registry */
3794 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3795 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3797 /* Hmmm. Does this mean that there are no service providers? */
3798 ERR(": no service providers?\n");
3799 return DP_OK;
3803 /* Traverse all the lobby providers we have available */
3804 for( dwIndex=0;
3805 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3806 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3807 ++dwIndex, sizeOfSubKeyName=51 )
3810 HKEY hkServiceProvider;
3811 GUID serviceProviderGUID;
3812 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3813 char returnBuffer[51];
3814 WCHAR buff[51];
3815 DPNAME dpName;
3816 HRESULT hr;
3818 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3819 LPVOID lpAddressBuffer = NULL;
3820 DWORD dwAddressBufferSize = 0;
3822 TRACE(" this time through: %s\n", subKeyName );
3824 /* Get a handle for this particular service provider */
3825 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3826 &hkServiceProvider ) != ERROR_SUCCESS )
3828 ERR(": what the heck is going on?\n" );
3829 continue;
3832 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3833 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3834 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3836 ERR(": missing GUID registry data members\n" );
3837 RegCloseKey(hkServiceProvider);
3838 continue;
3840 RegCloseKey(hkServiceProvider);
3842 /* FIXME: Check return types to ensure we're interpreting data right */
3843 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3844 CLSIDFromString( buff, &serviceProviderGUID );
3845 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3847 /* Fill in the DPNAME struct for the service provider */
3848 dpName.dwSize = sizeof( dpName );
3849 dpName.dwFlags = 0;
3850 dpName.u1.lpszShortNameA = subKeyName;
3851 dpName.u2.lpszLongNameA = NULL;
3853 /* Create the compound address for the service provider.
3854 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3855 nast stuff. This may be why the native dll just gets around this little bit by
3856 allocating an 80 byte buffer which isn't even a filled with a valid compound
3857 address. Oh well. Creating a proper compound address is the way to go anyways
3858 despite this method taking slightly more heap space and realtime :) */
3860 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3861 dpCompoundAddress.dwDataSize = sizeof( GUID );
3862 dpCompoundAddress.lpData = &serviceProviderGUID;
3864 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3865 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3867 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3868 return hr;
3871 /* Now allocate the buffer */
3872 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3874 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3875 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3877 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3878 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3879 return hr;
3882 /* The enumeration will return FALSE if we are not to continue */
3883 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3884 &dpName, dwFlags, lpContext ) )
3886 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3887 return DP_OK;
3889 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3893 return DP_OK;
3896 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3897 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3899 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3900 FIXME("(%p)->(%p,%p,%p,0x%08x): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3901 return DP_OK;
3904 static HRESULT DP_IF_EnumGroupsInGroup
3905 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3906 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3907 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3909 lpGroupList lpGList;
3910 lpGroupData lpGData;
3912 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
3913 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3914 lpContext, dwFlags, bAnsi );
3916 if( This->dp2->connectionInitialized == NO_PROVIDER )
3918 return DPERR_UNINITIALIZED;
3921 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3923 return DPERR_INVALIDGROUP;
3926 if( DPQ_IS_EMPTY( lpGData->groups ) )
3928 return DP_OK;
3931 lpGList = DPQ_FIRST( lpGData->groups );
3933 for( ;; )
3935 /* FIXME: Should check dwFlags for match here */
3937 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3938 &lpGList->lpGData->name, dwFlags,
3939 lpContext ) )
3941 return DP_OK; /* User requested break */
3944 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3946 break;
3949 lpGList = DPQ_NEXT( lpGList->groups );
3953 return DP_OK;
3956 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
3957 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3958 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3959 DWORD dwFlags )
3961 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3962 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3963 lpEnumPlayersCallback2, lpContext, dwFlags,
3964 TRUE );
3967 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3968 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3969 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3970 DWORD dwFlags )
3972 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3973 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3974 lpEnumPlayersCallback2, lpContext, dwFlags,
3975 FALSE );
3978 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
3979 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3981 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3982 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3983 return DP_OK;
3986 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
3987 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3989 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3990 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3991 return DP_OK;
3994 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
3995 REFGUID guidDataType,
3996 DWORD dwDataSize,
3997 LPCVOID lpData,
3998 LPVOID lpContext )
4000 /* Looking for the GUID of the provider to load */
4001 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
4002 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
4005 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4006 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
4008 if( dwDataSize != sizeof( GUID ) )
4010 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4013 memcpy( lpContext, lpData, dwDataSize );
4015 /* There shouldn't be more than 1 GUID/compound address */
4016 return FALSE;
4019 /* Still waiting for what we want */
4020 return TRUE;
4024 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4025 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4027 UINT i;
4028 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4029 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4030 LPCSTR guidDataSubKey = "Guid";
4031 LPCSTR majVerDataSubKey = "dwReserved1";
4032 LPCSTR minVerDataSubKey = "dwReserved2";
4033 LPCSTR pathSubKey = "Path";
4035 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4037 /* FIXME: Cloned code with a quick hack. */
4038 for( i=0; i<2; i++ )
4040 HKEY hkResult;
4041 LPCSTR searchSubKey;
4042 char subKeyName[51];
4043 DWORD dwIndex, sizeOfSubKeyName=50;
4044 FILETIME filetime;
4046 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4047 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4050 /* Need to loop over the service providers in the registry */
4051 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4052 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4054 /* Hmmm. Does this mean that there are no service providers? */
4055 ERR(": no service providers?\n");
4056 return 0;
4059 /* Traverse all the service providers we have available */
4060 for( dwIndex=0;
4061 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4062 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4063 ++dwIndex, sizeOfSubKeyName=51 )
4066 HKEY hkServiceProvider;
4067 GUID serviceProviderGUID;
4068 DWORD returnType, sizeOfReturnBuffer = 255;
4069 char returnBuffer[256];
4070 WCHAR buff[51];
4071 DWORD dwTemp, len;
4073 TRACE(" this time through: %s\n", subKeyName );
4075 /* Get a handle for this particular service provider */
4076 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4077 &hkServiceProvider ) != ERROR_SUCCESS )
4079 ERR(": what the heck is going on?\n" );
4080 continue;
4083 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4084 NULL, &returnType, (LPBYTE)returnBuffer,
4085 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4087 ERR(": missing GUID registry data members\n" );
4088 continue;
4091 /* FIXME: Check return types to ensure we're interpreting data right */
4092 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4093 CLSIDFromString( buff, &serviceProviderGUID );
4094 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4096 /* Determine if this is the Service Provider that the user asked for */
4097 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4099 continue;
4102 if( i == 0 ) /* DP SP */
4104 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4105 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4106 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4109 sizeOfReturnBuffer = 255;
4111 /* Get dwReserved1 */
4112 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4113 NULL, &returnType, (LPBYTE)returnBuffer,
4114 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4116 ERR(": missing dwReserved1 registry data members\n") ;
4117 continue;
4120 if( i == 0 )
4121 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4123 sizeOfReturnBuffer = 255;
4125 /* Get dwReserved2 */
4126 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4127 NULL, &returnType, (LPBYTE)returnBuffer,
4128 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4130 ERR(": missing dwReserved1 registry data members\n") ;
4131 continue;
4134 if( i == 0 )
4135 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4137 sizeOfReturnBuffer = 255;
4139 /* Get the path for this service provider */
4140 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4141 NULL, NULL, (LPBYTE)returnBuffer,
4142 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4144 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4145 continue;
4148 TRACE( "Loading %s\n", returnBuffer );
4149 return LoadLibraryA( returnBuffer );
4153 return 0;
4156 static
4157 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4159 HRESULT hr;
4160 LPDPSP_SPINIT SPInit;
4162 /* Initialize the service provider by calling SPInit */
4163 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4165 if( SPInit == NULL )
4167 ERR( "Service provider doesn't provide SPInit interface?\n" );
4168 FreeLibrary( hServiceProvider );
4169 return DPERR_UNAVAILABLE;
4172 TRACE( "Calling SPInit (DP SP entry point)\n" );
4174 hr = (*SPInit)( &This->dp2->spData );
4176 if( FAILED(hr) )
4178 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4179 FreeLibrary( hServiceProvider );
4180 return hr;
4183 /* FIXME: Need to verify the sanity of the returned callback table
4184 * using IsBadCodePtr */
4185 This->dp2->bSPInitialized = TRUE;
4187 /* This interface is now initialized as a DP object */
4188 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4190 /* Store the handle of the module so that we can unload it later */
4191 This->dp2->hServiceProvider = hServiceProvider;
4193 return hr;
4196 static
4197 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4199 HRESULT hr;
4200 LPSP_INIT DPLSPInit;
4202 /* Initialize the service provider by calling SPInit */
4203 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4205 if( DPLSPInit == NULL )
4207 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4208 FreeLibrary( hLobbyProvider );
4209 return DPERR_UNAVAILABLE;
4212 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4214 hr = (*DPLSPInit)( &This->dp2->dplspData );
4216 if( FAILED(hr) )
4218 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4219 FreeLibrary( hLobbyProvider );
4220 return hr;
4223 /* FIXME: Need to verify the sanity of the returned callback table
4224 * using IsBadCodePtr */
4226 This->dp2->bDPLSPInitialized = TRUE;
4228 /* This interface is now initialized as a lobby object */
4229 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4231 /* Store the handle of the module so that we can unload it later */
4232 This->dp2->hDPLobbyProvider = hLobbyProvider;
4234 return hr;
4237 static HRESULT DP_IF_InitializeConnection
4238 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4240 HMODULE hServiceProvider;
4241 HRESULT hr;
4242 GUID guidSP;
4243 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4244 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4246 TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4248 if ( lpConnection == NULL )
4250 return DPERR_INVALIDPARAMS;
4253 if( dwFlags != 0 )
4255 return DPERR_INVALIDFLAGS;
4258 if( This->dp2->connectionInitialized != NO_PROVIDER )
4260 return DPERR_ALREADYINITIALIZED;
4263 /* Find out what the requested SP is and how large this buffer is */
4264 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4265 dwAddrSize, &guidSP );
4267 if( FAILED(hr) )
4269 ERR( "Invalid compound address?\n" );
4270 return DPERR_UNAVAILABLE;
4273 /* Load the service provider */
4274 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4276 if( hServiceProvider == 0 )
4278 ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4279 return DPERR_UNAVAILABLE;
4282 if( bIsDpSp )
4284 /* Fill in what we can of the Service Provider required information.
4285 * The rest was be done in DP_LoadSP
4287 This->dp2->spData.lpAddress = lpConnection;
4288 This->dp2->spData.dwAddressSize = dwAddrSize;
4289 This->dp2->spData.lpGuid = &guidSP;
4291 hr = DP_InitializeDPSP( This, hServiceProvider );
4293 else
4295 This->dp2->dplspData.lpAddress = lpConnection;
4297 hr = DP_InitializeDPLSP( This, hServiceProvider );
4300 if( FAILED(hr) )
4302 return hr;
4305 return DP_OK;
4308 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4309 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4311 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4313 /* This may not be externally invoked once either an SP or LP is initialized */
4314 if( This->dp2->connectionInitialized != NO_PROVIDER )
4316 return DPERR_ALREADYINITIALIZED;
4319 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4322 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4323 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4325 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4327 /* This may not be externally invoked once either an SP or LP is initialized */
4328 if( This->dp2->connectionInitialized != NO_PROVIDER )
4330 return DPERR_ALREADYINITIALIZED;
4333 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4336 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4337 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4338 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4340 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4341 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4344 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4345 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4346 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4348 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4349 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4352 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4353 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4355 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4356 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4357 return DP_OK;
4360 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4361 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4363 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4364 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4365 return DP_OK;
4368 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4369 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4371 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4372 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4373 return DP_OK;
4376 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4377 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4379 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4380 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4381 return DP_OK;
4384 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4385 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4387 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4388 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4389 return DP_OK;
4392 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4393 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4395 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4396 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4397 return DP_OK;
4400 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4401 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4403 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4404 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4405 return DP_OK;
4408 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4409 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4411 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4412 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4413 return DP_OK;
4416 static HRESULT DP_IF_GetGroupParent
4417 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4418 BOOL bAnsi )
4420 lpGroupData lpGData;
4422 TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4424 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4426 return DPERR_INVALIDGROUP;
4429 *lpidGroup = lpGData->dpid;
4431 return DP_OK;
4434 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4435 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4437 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4438 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4440 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4441 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4443 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4444 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4447 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4448 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4450 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4451 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4452 return DP_OK;
4455 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4456 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4458 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4459 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4460 return DP_OK;
4463 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4464 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4466 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4467 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4468 return DP_OK;
4471 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4472 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4474 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4475 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4476 return DP_OK;
4479 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4480 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4482 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4483 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4484 return DP_OK;
4487 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4488 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4490 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4491 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4492 return DP_OK;
4495 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4496 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4498 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4499 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4500 return DP_OK;
4503 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4504 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4506 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4507 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4508 return DP_OK;
4511 static HRESULT DP_SendEx
4512 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4513 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4514 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4516 BOOL bValidDestination = FALSE;
4518 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4519 ": stub\n",
4520 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4521 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4523 if( This->dp2->connectionInitialized == NO_PROVIDER )
4525 return DPERR_UNINITIALIZED;
4528 /* FIXME: Add parameter checking */
4529 /* FIXME: First call to this needs to acquire a message id which will be
4530 * used for multiple sends
4533 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4535 /* Verify that the message is being sent from a valid local player. The
4536 * from player may be anonymous DPID_UNKNOWN
4538 if( idFrom != DPID_UNKNOWN )
4540 if( DP_FindPlayer( This, idFrom ) == NULL )
4542 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4543 return DPERR_INVALIDPLAYER;
4547 /* Verify that the message is being sent to a valid player, group or to
4548 * everyone. If it's valid, send it to those players.
4550 if( idTo == DPID_ALLPLAYERS )
4552 bValidDestination = TRUE;
4554 /* See if SP has the ability to multicast. If so, use it */
4555 if( This->dp2->spData.lpCB->SendToGroupEx )
4557 FIXME( "Use group sendex to group 0\n" );
4559 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4561 FIXME( "Use obsolete group send to group 0\n" );
4563 else /* No multicast, multiplicate */
4565 /* Send to all players we know about */
4566 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4570 if( ( !bValidDestination ) &&
4571 ( DP_FindPlayer( This, idTo ) != NULL )
4574 /* Have the service provider send this message */
4575 /* FIXME: Could optimize for local interface sends */
4576 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4577 dwTimeout, lpContext, lpdwMsgID );
4580 if( ( !bValidDestination ) &&
4581 ( DP_FindAnyGroup( This, idTo ) != NULL )
4584 bValidDestination = TRUE;
4586 /* See if SP has the ability to multicast. If so, use it */
4587 if( This->dp2->spData.lpCB->SendToGroupEx )
4589 FIXME( "Use group sendex\n" );
4591 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4593 FIXME( "Use obsolete group send to group\n" );
4595 else /* No multicast, multiplicate */
4597 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4600 #if 0
4601 if( bExpectReply )
4603 DWORD dwWaitReturn;
4605 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4607 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4608 if( dwWaitReturn != WAIT_OBJECT_0 )
4610 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4613 #endif
4616 if( !bValidDestination )
4618 return DPERR_INVALIDPLAYER;
4620 else
4622 /* FIXME: Should return what the send returned */
4623 return DP_OK;
4628 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4629 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4630 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4631 LPVOID lpContext, LPDWORD lpdwMsgID )
4633 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4634 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4635 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4638 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4639 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4640 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4641 LPVOID lpContext, LPDWORD lpdwMsgID )
4643 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4644 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4645 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4648 static HRESULT DP_SP_SendEx
4649 ( IDirectPlay2Impl* This, DWORD dwFlags,
4650 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4651 LPVOID lpContext, LPDWORD lpdwMsgID )
4653 LPDPMSG lpMElem;
4655 FIXME( ": stub\n" );
4657 /* FIXME: This queuing should only be for async messages */
4659 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4660 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4662 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4664 /* FIXME: Need to queue based on priority */
4665 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4667 return DP_OK;
4670 static HRESULT DP_IF_GetMessageQueue
4671 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4672 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4674 HRESULT hr = DP_OK;
4676 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4677 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4679 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4680 /* FIXME: What about sends which are not immediate? */
4682 if( This->dp2->spData.lpCB->GetMessageQueue )
4684 DPSP_GETMESSAGEQUEUEDATA data;
4686 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4688 /* FIXME: None of this is documented :( */
4690 data.lpISP = This->dp2->spData.lpISP;
4691 data.dwFlags = dwFlags;
4692 data.idFrom = idFrom;
4693 data.idTo = idTo;
4694 data.lpdwNumMsgs = lpdwNumMsgs;
4695 data.lpdwNumBytes = lpdwNumBytes;
4697 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4699 else
4701 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4704 return hr;
4707 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4708 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4709 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4711 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4712 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4713 lpdwNumBytes, TRUE );
4716 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4717 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4718 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4720 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4721 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4722 lpdwNumBytes, FALSE );
4725 static HRESULT DP_IF_CancelMessage
4726 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4727 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4729 HRESULT hr = DP_OK;
4731 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4732 This, dwMsgID, dwFlags, bAnsi );
4734 if( This->dp2->spData.lpCB->Cancel )
4736 DPSP_CANCELDATA data;
4738 TRACE( "Calling SP Cancel\n" );
4740 /* FIXME: Undocumented callback */
4742 data.lpISP = This->dp2->spData.lpISP;
4743 data.dwFlags = dwFlags;
4744 data.lprglpvSPMsgID = NULL;
4745 data.cSPMsgID = dwMsgID;
4746 data.dwMinPriority = dwMinPriority;
4747 data.dwMaxPriority = dwMaxPriority;
4749 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4751 else
4753 FIXME( "SP doesn't implement Cancel\n" );
4756 return hr;
4759 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4760 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4762 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4764 if( dwFlags != 0 )
4766 return DPERR_INVALIDFLAGS;
4769 if( dwMsgID == 0 )
4771 dwFlags |= DPCANCELSEND_ALL;
4774 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4777 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4778 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4780 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4782 if( dwFlags != 0 )
4784 return DPERR_INVALIDFLAGS;
4787 if( dwMsgID == 0 )
4789 dwFlags |= DPCANCELSEND_ALL;
4792 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4795 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4796 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4797 DWORD dwFlags )
4799 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4801 if( dwFlags != 0 )
4803 return DPERR_INVALIDFLAGS;
4806 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4807 dwMaxPriority, TRUE );
4810 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4811 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4812 DWORD dwFlags )
4814 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4816 if( dwFlags != 0 )
4818 return DPERR_INVALIDFLAGS;
4821 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4822 dwMaxPriority, FALSE );
4825 /* Note: Hack so we can reuse the old functions without compiler warnings */
4826 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4827 # define XCAST(fun) (typeof(directPlay2WVT.fun))
4828 #else
4829 # define XCAST(fun) (void*)
4830 #endif
4832 static const IDirectPlay2Vtbl directPlay2WVT =
4834 XCAST(QueryInterface)DP_QueryInterface,
4835 XCAST(AddRef)DP_AddRef,
4836 XCAST(Release)DP_Release,
4838 DirectPlay2WImpl_AddPlayerToGroup,
4839 DirectPlay2WImpl_Close,
4840 DirectPlay2WImpl_CreateGroup,
4841 DirectPlay2WImpl_CreatePlayer,
4842 DirectPlay2WImpl_DeletePlayerFromGroup,
4843 DirectPlay2WImpl_DestroyGroup,
4844 DirectPlay2WImpl_DestroyPlayer,
4845 DirectPlay2WImpl_EnumGroupPlayers,
4846 DirectPlay2WImpl_EnumGroups,
4847 DirectPlay2WImpl_EnumPlayers,
4848 DirectPlay2WImpl_EnumSessions,
4849 DirectPlay2WImpl_GetCaps,
4850 DirectPlay2WImpl_GetGroupData,
4851 DirectPlay2WImpl_GetGroupName,
4852 DirectPlay2WImpl_GetMessageCount,
4853 DirectPlay2WImpl_GetPlayerAddress,
4854 DirectPlay2WImpl_GetPlayerCaps,
4855 DirectPlay2WImpl_GetPlayerData,
4856 DirectPlay2WImpl_GetPlayerName,
4857 DirectPlay2WImpl_GetSessionDesc,
4858 DirectPlay2WImpl_Initialize,
4859 DirectPlay2WImpl_Open,
4860 DirectPlay2WImpl_Receive,
4861 DirectPlay2WImpl_Send,
4862 DirectPlay2WImpl_SetGroupData,
4863 DirectPlay2WImpl_SetGroupName,
4864 DirectPlay2WImpl_SetPlayerData,
4865 DirectPlay2WImpl_SetPlayerName,
4866 DirectPlay2WImpl_SetSessionDesc
4868 #undef XCAST
4870 /* Note: Hack so we can reuse the old functions without compiler warnings */
4871 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4872 # define XCAST(fun) (typeof(directPlay2AVT.fun))
4873 #else
4874 # define XCAST(fun) (void*)
4875 #endif
4877 static const IDirectPlay2Vtbl directPlay2AVT =
4879 XCAST(QueryInterface)DP_QueryInterface,
4880 XCAST(AddRef)DP_AddRef,
4881 XCAST(Release)DP_Release,
4883 DirectPlay2AImpl_AddPlayerToGroup,
4884 DirectPlay2AImpl_Close,
4885 DirectPlay2AImpl_CreateGroup,
4886 DirectPlay2AImpl_CreatePlayer,
4887 DirectPlay2AImpl_DeletePlayerFromGroup,
4888 DirectPlay2AImpl_DestroyGroup,
4889 DirectPlay2AImpl_DestroyPlayer,
4890 DirectPlay2AImpl_EnumGroupPlayers,
4891 DirectPlay2AImpl_EnumGroups,
4892 DirectPlay2AImpl_EnumPlayers,
4893 DirectPlay2AImpl_EnumSessions,
4894 DirectPlay2AImpl_GetCaps,
4895 DirectPlay2AImpl_GetGroupData,
4896 DirectPlay2AImpl_GetGroupName,
4897 DirectPlay2AImpl_GetMessageCount,
4898 DirectPlay2AImpl_GetPlayerAddress,
4899 DirectPlay2AImpl_GetPlayerCaps,
4900 DirectPlay2AImpl_GetPlayerData,
4901 DirectPlay2AImpl_GetPlayerName,
4902 DirectPlay2AImpl_GetSessionDesc,
4903 DirectPlay2AImpl_Initialize,
4904 DirectPlay2AImpl_Open,
4905 DirectPlay2AImpl_Receive,
4906 DirectPlay2AImpl_Send,
4907 DirectPlay2AImpl_SetGroupData,
4908 DirectPlay2AImpl_SetGroupName,
4909 DirectPlay2AImpl_SetPlayerData,
4910 DirectPlay2AImpl_SetPlayerName,
4911 DirectPlay2AImpl_SetSessionDesc
4913 #undef XCAST
4916 /* Note: Hack so we can reuse the old functions without compiler warnings */
4917 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4918 # define XCAST(fun) (typeof(directPlay3AVT.fun))
4919 #else
4920 # define XCAST(fun) (void*)
4921 #endif
4923 static const IDirectPlay3Vtbl directPlay3AVT =
4925 XCAST(QueryInterface)DP_QueryInterface,
4926 XCAST(AddRef)DP_AddRef,
4927 XCAST(Release)DP_Release,
4929 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
4930 XCAST(Close)DirectPlay2AImpl_Close,
4931 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
4932 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
4933 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
4934 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
4935 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
4936 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
4937 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
4938 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
4939 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
4940 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
4941 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
4942 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
4943 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
4944 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
4945 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
4946 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
4947 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
4948 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
4949 XCAST(Initialize)DirectPlay2AImpl_Initialize,
4950 XCAST(Open)DirectPlay2AImpl_Open,
4951 XCAST(Receive)DirectPlay2AImpl_Receive,
4952 XCAST(Send)DirectPlay2AImpl_Send,
4953 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
4954 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
4955 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
4956 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
4957 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
4959 DirectPlay3AImpl_AddGroupToGroup,
4960 DirectPlay3AImpl_CreateGroupInGroup,
4961 DirectPlay3AImpl_DeleteGroupFromGroup,
4962 DirectPlay3AImpl_EnumConnections,
4963 DirectPlay3AImpl_EnumGroupsInGroup,
4964 DirectPlay3AImpl_GetGroupConnectionSettings,
4965 DirectPlay3AImpl_InitializeConnection,
4966 DirectPlay3AImpl_SecureOpen,
4967 DirectPlay3AImpl_SendChatMessage,
4968 DirectPlay3AImpl_SetGroupConnectionSettings,
4969 DirectPlay3AImpl_StartSession,
4970 DirectPlay3AImpl_GetGroupFlags,
4971 DirectPlay3AImpl_GetGroupParent,
4972 DirectPlay3AImpl_GetPlayerAccount,
4973 DirectPlay3AImpl_GetPlayerFlags
4975 #undef XCAST
4977 /* Note: Hack so we can reuse the old functions without compiler warnings */
4978 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4979 # define XCAST(fun) (typeof(directPlay3WVT.fun))
4980 #else
4981 # define XCAST(fun) (void*)
4982 #endif
4983 static const IDirectPlay3Vtbl directPlay3WVT =
4985 XCAST(QueryInterface)DP_QueryInterface,
4986 XCAST(AddRef)DP_AddRef,
4987 XCAST(Release)DP_Release,
4989 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
4990 XCAST(Close)DirectPlay2WImpl_Close,
4991 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
4992 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
4993 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
4994 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
4995 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
4996 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
4997 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
4998 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
4999 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5000 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5001 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5002 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5003 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5004 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5005 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5006 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5007 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5008 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5009 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5010 XCAST(Open)DirectPlay2WImpl_Open,
5011 XCAST(Receive)DirectPlay2WImpl_Receive,
5012 XCAST(Send)DirectPlay2WImpl_Send,
5013 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5014 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5015 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5016 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5017 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5019 DirectPlay3WImpl_AddGroupToGroup,
5020 DirectPlay3WImpl_CreateGroupInGroup,
5021 DirectPlay3WImpl_DeleteGroupFromGroup,
5022 DirectPlay3WImpl_EnumConnections,
5023 DirectPlay3WImpl_EnumGroupsInGroup,
5024 DirectPlay3WImpl_GetGroupConnectionSettings,
5025 DirectPlay3WImpl_InitializeConnection,
5026 DirectPlay3WImpl_SecureOpen,
5027 DirectPlay3WImpl_SendChatMessage,
5028 DirectPlay3WImpl_SetGroupConnectionSettings,
5029 DirectPlay3WImpl_StartSession,
5030 DirectPlay3WImpl_GetGroupFlags,
5031 DirectPlay3WImpl_GetGroupParent,
5032 DirectPlay3WImpl_GetPlayerAccount,
5033 DirectPlay3WImpl_GetPlayerFlags
5035 #undef XCAST
5037 /* Note: Hack so we can reuse the old functions without compiler warnings */
5038 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5039 # define XCAST(fun) (typeof(directPlay4WVT.fun))
5040 #else
5041 # define XCAST(fun) (void*)
5042 #endif
5043 static const IDirectPlay4Vtbl directPlay4WVT =
5045 XCAST(QueryInterface)DP_QueryInterface,
5046 XCAST(AddRef)DP_AddRef,
5047 XCAST(Release)DP_Release,
5049 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5050 XCAST(Close)DirectPlay2WImpl_Close,
5051 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5052 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5053 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5054 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5055 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5056 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5057 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5058 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5059 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5060 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5061 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5062 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5063 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5064 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5065 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5066 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5067 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5068 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5069 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5070 XCAST(Open)DirectPlay2WImpl_Open,
5071 XCAST(Receive)DirectPlay2WImpl_Receive,
5072 XCAST(Send)DirectPlay2WImpl_Send,
5073 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5074 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5075 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5076 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5077 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5079 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5080 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5081 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5082 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5083 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5084 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5085 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5086 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5087 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5088 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5089 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5090 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5091 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5092 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5093 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5095 DirectPlay4WImpl_GetGroupOwner,
5096 DirectPlay4WImpl_SetGroupOwner,
5097 DirectPlay4WImpl_SendEx,
5098 DirectPlay4WImpl_GetMessageQueue,
5099 DirectPlay4WImpl_CancelMessage,
5100 DirectPlay4WImpl_CancelPriority
5102 #undef XCAST
5105 /* Note: Hack so we can reuse the old functions without compiler warnings */
5106 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5107 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5108 #else
5109 # define XCAST(fun) (void*)
5110 #endif
5111 static const IDirectPlay4Vtbl directPlay4AVT =
5113 XCAST(QueryInterface)DP_QueryInterface,
5114 XCAST(AddRef)DP_AddRef,
5115 XCAST(Release)DP_Release,
5117 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5118 XCAST(Close)DirectPlay2AImpl_Close,
5119 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5120 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5121 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5122 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5123 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5124 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5125 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5126 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5127 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5128 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5129 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5130 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5131 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5132 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5133 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5134 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5135 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5136 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5137 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5138 XCAST(Open)DirectPlay2AImpl_Open,
5139 XCAST(Receive)DirectPlay2AImpl_Receive,
5140 XCAST(Send)DirectPlay2AImpl_Send,
5141 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5142 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5143 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5144 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5145 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5147 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5148 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5149 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5150 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5151 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5152 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5153 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5154 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5155 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5156 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5157 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5158 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5159 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5160 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5161 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5163 DirectPlay4AImpl_GetGroupOwner,
5164 DirectPlay4AImpl_SetGroupOwner,
5165 DirectPlay4AImpl_SendEx,
5166 DirectPlay4AImpl_GetMessageQueue,
5167 DirectPlay4AImpl_CancelMessage,
5168 DirectPlay4AImpl_CancelPriority
5170 #undef XCAST
5172 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5173 DPID idPlayer,
5174 LPVOID* lplpData )
5176 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5178 if( lpPlayer == NULL )
5180 return DPERR_INVALIDPLAYER;
5183 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5185 return DP_OK;
5188 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5189 DPID idPlayer,
5190 LPVOID lpData )
5192 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5194 if( lpPlayer == NULL )
5196 return DPERR_INVALIDPLAYER;
5199 lpPlayer->lpPData->lpSPPlayerData = lpData;
5201 return DP_OK;
5204 /***************************************************************************
5205 * DirectPlayEnumerateAW
5207 * The pointer to the structure lpContext will be filled with the
5208 * appropriate data for each service offered by the OS. These services are
5209 * not necessarily available on this particular machine but are defined
5210 * as simple service providers under the "Service Providers" registry key.
5211 * This structure is then passed to lpEnumCallback for each of the different
5212 * services.
5214 * This API is useful only for applications written using DirectX3 or
5215 * worse. It is superseded by IDirectPlay3::EnumConnections which also
5216 * gives information on the actual connections.
5218 * defn of a service provider:
5219 * A dynamic-link library used by DirectPlay to communicate over a network.
5220 * The service provider contains all the network-specific code required
5221 * to send and receive messages. Online services and network operators can
5222 * supply service providers to use specialized hardware, protocols, communications
5223 * media, and network resources.
5226 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5227 LPDPENUMDPCALLBACKW lpEnumCallbackW,
5228 LPVOID lpContext)
5230 HKEY hkResult;
5231 static const WCHAR searchSubKey[] = {
5232 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5233 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5234 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5235 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5236 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5237 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5239 DWORD dwIndex;
5240 FILETIME filetime;
5242 char *descriptionA = NULL;
5243 DWORD max_sizeOfDescriptionA = 0;
5244 WCHAR *descriptionW = NULL;
5245 DWORD max_sizeOfDescriptionW = 0;
5247 if (!lpEnumCallbackA && !lpEnumCallbackW)
5249 return DPERR_INVALIDPARAMS;
5252 /* Need to loop over the service providers in the registry */
5253 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5254 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5256 /* Hmmm. Does this mean that there are no service providers? */
5257 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5258 return DPERR_GENERIC;
5261 /* Traverse all the service providers we have available */
5262 dwIndex = 0;
5263 while (1)
5265 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5266 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5267 HKEY hkServiceProvider;
5268 GUID serviceProviderGUID;
5269 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5270 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5271 LONG ret_value;
5273 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5274 NULL, NULL, NULL, &filetime);
5275 if (ret_value == ERROR_NO_MORE_ITEMS)
5276 break;
5277 else if (ret_value != ERROR_SUCCESS)
5279 ERR(": could not enumerate on service provider key.\n");
5280 return DPERR_EXCEPTION;
5282 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5284 /* Open the key for this service provider */
5285 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5287 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5288 continue;
5291 /* Get the GUID from the registry */
5292 if (RegQueryValueExW(hkServiceProvider, guidKey,
5293 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5295 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5296 continue;
5298 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5300 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5301 continue;
5303 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5305 /* The enumeration will return FALSE if we are not to continue.
5307 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5308 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5309 * I think that it simply means that they are in-line with DirectX 6.0
5311 if (lpEnumCallbackA)
5313 DWORD sizeOfDescription = 0;
5315 /* Note that this is the A case of this function, so use the A variant to get the description string */
5316 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5317 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5319 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5320 continue;
5322 if (sizeOfDescription > max_sizeOfDescriptionA)
5324 HeapFree(GetProcessHeap(), 0, descriptionA);
5325 max_sizeOfDescriptionA = sizeOfDescription;
5327 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5328 RegQueryValueExA(hkServiceProvider, "DescriptionA",
5329 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5331 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5332 goto end;
5334 else
5336 DWORD sizeOfDescription = 0;
5338 if (RegQueryValueExW(hkServiceProvider, descW,
5339 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5341 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5342 continue;
5344 if (sizeOfDescription > max_sizeOfDescriptionW)
5346 HeapFree(GetProcessHeap(), 0, descriptionW);
5347 max_sizeOfDescriptionW = sizeOfDescription;
5349 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5350 RegQueryValueExW(hkServiceProvider, descW,
5351 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5353 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5354 goto end;
5357 dwIndex++;
5360 end:
5361 HeapFree(GetProcessHeap(), 0, descriptionA);
5362 HeapFree(GetProcessHeap(), 0, descriptionW);
5364 return DP_OK;
5367 /***************************************************************************
5368 * DirectPlayEnumerate [DPLAYX.9]
5369 * DirectPlayEnumerateA [DPLAYX.2]
5371 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5373 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5375 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5378 /***************************************************************************
5379 * DirectPlayEnumerateW [DPLAYX.3]
5381 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5383 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5385 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5388 typedef struct tagCreateEnum
5390 LPVOID lpConn;
5391 LPCGUID lpGuid;
5392 } CreateEnumData, *lpCreateEnumData;
5394 /* Find and copy the matching connection for the SP guid */
5395 static BOOL CALLBACK cbDPCreateEnumConnections(
5396 LPCGUID lpguidSP,
5397 LPVOID lpConnection,
5398 DWORD dwConnectionSize,
5399 LPCDPNAME lpName,
5400 DWORD dwFlags,
5401 LPVOID lpContext)
5403 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5405 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5407 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5409 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5410 dwConnectionSize );
5411 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5413 /* Found the record that we were looking for */
5414 return FALSE;
5417 /* Haven't found what were looking for yet */
5418 return TRUE;
5422 /***************************************************************************
5423 * DirectPlayCreate [DPLAYX.1]
5426 HRESULT WINAPI DirectPlayCreate
5427 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5429 HRESULT hr;
5430 LPDIRECTPLAY3A lpDP3A;
5431 CreateEnumData cbData;
5433 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5435 if( pUnk != NULL )
5437 return CLASS_E_NOAGGREGATION;
5440 if( (lplpDP == NULL) || (lpGUID == NULL) )
5442 return DPERR_INVALIDPARAMS;
5446 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5447 give them an IDirectPlay2A object and hope that doesn't cause problems */
5448 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5450 return DPERR_UNAVAILABLE;
5453 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5455 /* The GUID_NULL means don't bind a service provider. Just return the
5456 interface as is */
5457 return DP_OK;
5460 /* Bind the desired service provider since lpGUID is non NULL */
5461 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5463 /* We're going to use a DP3 interface */
5464 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5465 (LPVOID*)&lpDP3A );
5466 if( FAILED(hr) )
5468 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5469 return hr;
5472 cbData.lpConn = NULL;
5473 cbData.lpGuid = lpGUID;
5475 /* We were given a service provider, find info about it... */
5476 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5477 &cbData, DPCONNECTION_DIRECTPLAY );
5478 if( ( FAILED(hr) ) ||
5479 ( cbData.lpConn == NULL )
5482 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5483 IDirectPlayX_Release( lpDP3A );
5484 return DPERR_UNAVAILABLE;
5487 /* Initialize the service provider */
5488 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5489 if( FAILED(hr) )
5491 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5492 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5493 IDirectPlayX_Release( lpDP3A );
5494 return hr;
5497 /* Release our version of the interface now that we're done with it */
5498 IDirectPlayX_Release( lpDP3A );
5499 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5501 return DP_OK;