wined3d: Get rid of ENTER_GL / LEAVE_GL.
[wine/multimedia.git] / dlls / dplayx / dplay.c
blob29212bc34b60dda0b5ad6227cdc93993a7832519
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->repliesExpected);
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 if( dwFlags & DPSET_LOCAL )
1131 lpGData->lpLocalData = lpData;
1132 lpGData->dwLocalDataSize = dwDataSize;
1134 else
1136 lpGData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
1137 CopyMemory( lpGData->lpRemoteData, lpData, dwDataSize );
1138 lpGData->dwRemoteDataSize = dwDataSize;
1144 /* This function will just create the storage for the new player. */
1145 static
1146 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1147 LPDPNAME lpName, DWORD dwFlags,
1148 HANDLE hEvent, BOOL bAnsi )
1150 lpPlayerData lpPData;
1152 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1154 /* Allocate the storage for the player and associate it with list element */
1155 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1156 if( lpPData == NULL )
1158 return NULL;
1161 /* Set the desired player ID */
1162 lpPData->dpid = *lpid;
1164 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1166 lpPData->dwFlags = dwFlags;
1168 /* If we were given an event handle, duplicate it */
1169 if( hEvent != 0 )
1171 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1172 GetCurrentProcess(), &lpPData->hEvent,
1173 0, FALSE, DUPLICATE_SAME_ACCESS )
1176 /* FIXME: Memory leak */
1177 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1181 /* Initialize the SP data section */
1182 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1184 TRACE( "Created player id 0x%08x\n", *lpid );
1186 if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1187 This->dp2->lpSessionDesc->dwCurrentPlayers++;
1189 return lpPData;
1192 /* Delete the contents of the DPNAME struct */
1193 static void
1194 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1196 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1197 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1200 /* This method assumes that all links to it are already deleted */
1201 static void
1202 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1204 lpPlayerList lpPList;
1206 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1208 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1210 if( lpPList == NULL )
1212 ERR( "DPID 0x%08x not found\n", dpid );
1213 return;
1216 /* Verify that this is the last reference to the data */
1217 if( --(lpPList->lpPData->uRef) )
1219 FIXME( "Why is this not the last reference to player?\n" );
1220 DebugBreak();
1223 /* Delete player */
1224 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1226 CloseHandle( lpPList->lpPData->hEvent );
1227 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1229 /* Delete Player List object */
1230 HeapFree( GetProcessHeap(), 0, lpPList );
1233 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1235 lpPlayerList lpPlayers;
1237 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1239 if(This->dp2->lpSysGroup == NULL)
1240 return NULL;
1242 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1244 return lpPlayers;
1247 /* Basic area for Dst must already be allocated */
1248 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1250 if( lpSrc == NULL )
1252 ZeroMemory( lpDst, sizeof( *lpDst ) );
1253 lpDst->dwSize = sizeof( *lpDst );
1254 return TRUE;
1257 if( lpSrc->dwSize != sizeof( *lpSrc) )
1259 return FALSE;
1262 /* Delete any existing pointers */
1263 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1264 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1266 /* Copy as required */
1267 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1269 if( bAnsi )
1271 if( lpSrc->u1.lpszShortNameA )
1273 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1274 strlen(lpSrc->u1.lpszShortNameA)+1 );
1275 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1277 if( lpSrc->u2.lpszLongNameA )
1279 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1280 strlen(lpSrc->u2.lpszLongNameA)+1 );
1281 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1284 else
1286 if( lpSrc->u1.lpszShortNameA )
1288 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1289 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1290 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1292 if( lpSrc->u2.lpszLongNameA )
1294 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1295 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1296 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1300 return TRUE;
1303 static void
1304 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1305 LPVOID lpData, DWORD dwDataSize )
1307 /* Clear out the data with this player */
1308 if( dwFlags & DPSET_LOCAL )
1310 if ( lpPData->dwLocalDataSize != 0 )
1312 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1313 lpPData->lpLocalData = NULL;
1314 lpPData->dwLocalDataSize = 0;
1317 else
1319 if( lpPData->dwRemoteDataSize != 0 )
1321 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1322 lpPData->lpRemoteData = NULL;
1323 lpPData->dwRemoteDataSize = 0;
1327 /* Reallocate for new data */
1328 if( lpData != NULL )
1331 if( dwFlags & DPSET_LOCAL )
1333 lpPData->lpLocalData = lpData;
1334 lpPData->dwLocalDataSize = dwDataSize;
1336 else
1338 lpPData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
1339 CopyMemory( lpPData->lpRemoteData, lpData, dwDataSize );
1340 lpPData->dwRemoteDataSize = dwDataSize;
1346 static HRESULT DP_IF_CreatePlayer
1347 ( IDirectPlay2Impl* This,
1348 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1349 LPDPID lpidPlayer,
1350 LPDPNAME lpPlayerName,
1351 HANDLE hEvent,
1352 LPVOID lpData,
1353 DWORD dwDataSize,
1354 DWORD dwFlags,
1355 BOOL bAnsi )
1357 HRESULT hr = DP_OK;
1358 lpPlayerData lpPData;
1359 lpPlayerList lpPList;
1360 DWORD dwCreateFlags = 0;
1362 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1363 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1364 dwDataSize, dwFlags, bAnsi );
1365 if( This->dp2->connectionInitialized == NO_PROVIDER )
1367 return DPERR_UNINITIALIZED;
1370 if( dwFlags == 0 )
1372 dwFlags = DPPLAYER_SPECTATOR;
1375 if( lpidPlayer == NULL )
1377 return DPERR_INVALIDPARAMS;
1381 /* Determine the creation flags for the player. These will be passed
1382 * to the name server if requesting a player id and to the SP when
1383 * informing it of the player creation
1386 if( dwFlags & DPPLAYER_SERVERPLAYER )
1388 if( *lpidPlayer == DPID_SERVERPLAYER )
1390 /* Server player for the host interface */
1391 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1393 else if( *lpidPlayer == DPID_NAME_SERVER )
1395 /* Name server - master of everything */
1396 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1398 else
1400 /* Server player for a non host interface */
1401 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1405 if( lpMsgHdr == NULL )
1406 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1409 /* Verify we know how to handle all the flags */
1410 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1411 ( dwFlags & DPPLAYER_SPECTATOR )
1415 /* Assume non fatal failure */
1416 ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1419 /* If the name is not specified, we must provide one */
1420 if( *lpidPlayer == DPID_UNKNOWN )
1422 /* If we are the session master, we dish out the group/player ids */
1423 if( This->dp2->bHostInterface )
1425 *lpidPlayer = DP_NextObjectId();
1427 else
1429 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1431 if( FAILED(hr) )
1433 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1434 return hr;
1438 else
1440 /* FIXME: Would be nice to perhaps verify that we don't already have
1441 * this player.
1445 /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
1446 player total */
1447 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1448 hEvent, bAnsi );
1450 if( lpPData == NULL )
1452 return DPERR_CANTADDPLAYER;
1455 /* Create the list object and link it in */
1456 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1457 if( lpPList == NULL )
1459 FIXME( "Memory leak\n" );
1460 return DPERR_CANTADDPLAYER;
1463 lpPData->uRef = 1;
1464 lpPList->lpPData = lpPData;
1466 /* Add the player to the system group */
1467 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1469 /* Update the information and send it to all players in the session */
1470 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1472 /* Let the SP know that we've created this player */
1473 if( This->dp2->spData.lpCB->CreatePlayer )
1475 DPSP_CREATEPLAYERDATA data;
1477 data.idPlayer = *lpidPlayer;
1478 data.dwFlags = dwCreateFlags;
1479 data.lpSPMessageHeader = lpMsgHdr;
1480 data.lpISP = This->dp2->spData.lpISP;
1482 TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1483 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1485 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1488 if( FAILED(hr) )
1490 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1491 return hr;
1494 /* Now let the SP know that this player is a member of the system group */
1495 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1497 DPSP_ADDPLAYERTOGROUPDATA data;
1499 data.idPlayer = *lpidPlayer;
1500 data.idGroup = DPID_SYSTEM_GROUP;
1501 data.lpISP = This->dp2->spData.lpISP;
1503 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1505 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1508 if( FAILED(hr) )
1510 ERR( "Failed to add player to sys group with sp: %s\n",
1511 DPLAYX_HresultToString(hr) );
1512 return hr;
1515 #if 1
1516 if( This->dp2->bHostInterface == FALSE )
1518 /* Let the name server know about the creation of this player */
1519 /* FIXME: Is this only to be done for the creation of a server player or
1520 * is this used for regular players? If only for server players, move
1521 * this call to DP_SecureOpen(...);
1523 #if 0
1524 TRACE( "Sending message to self to get my addr\n" );
1525 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1526 #endif
1528 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1530 #else
1531 /* Inform all other peers of the creation of a new player. If there are
1532 * no peers keep this quiet.
1533 * Also, if this was a remote event, no need to rebroadcast it.
1535 if( ( lpMsgHdr == NULL ) &&
1536 This->dp2->lpSessionDesc &&
1537 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1539 DPMSG_CREATEPLAYERORGROUP msg;
1540 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1542 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1543 msg.dpId = *lpidPlayer;
1544 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1545 msg.lpData = lpData;
1546 msg.dwDataSize = dwDataSize;
1547 msg.dpnName = *lpPlayerName;
1548 msg.dpIdParent = DPID_NOPARENT_GROUP;
1549 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1551 /* FIXME: Correct to just use send effectively? */
1552 /* FIXME: Should size include data w/ message or just message "header" */
1553 /* FIXME: Check return code */
1554 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1555 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1557 #endif
1559 return hr;
1562 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1563 ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1564 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1566 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1568 if( lpidPlayer == NULL )
1570 return DPERR_INVALIDPARAMS;
1573 if( dwFlags & DPPLAYER_SERVERPLAYER )
1575 *lpidPlayer = DPID_SERVERPLAYER;
1577 else
1579 *lpidPlayer = DPID_UNKNOWN;
1582 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1583 lpData, dwDataSize, dwFlags, TRUE );
1586 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1587 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1588 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1590 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1592 if( lpidPlayer == NULL )
1594 return DPERR_INVALIDPARAMS;
1597 if( dwFlags & DPPLAYER_SERVERPLAYER )
1599 *lpidPlayer = DPID_SERVERPLAYER;
1601 else
1603 *lpidPlayer = DPID_UNKNOWN;
1606 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1607 lpData, dwDataSize, dwFlags, FALSE );
1610 static DPID DP_GetRemoteNextObjectId(void)
1612 FIXME( ":stub\n" );
1614 /* Hack solution */
1615 return DP_NextObjectId();
1618 static HRESULT DP_IF_DeletePlayerFromGroup
1619 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1620 DPID idPlayer, BOOL bAnsi )
1622 HRESULT hr = DP_OK;
1624 lpGroupData lpGData;
1625 lpPlayerList lpPList;
1627 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
1628 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1630 /* Find the group */
1631 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1633 return DPERR_INVALIDGROUP;
1636 /* Find the player */
1637 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1639 return DPERR_INVALIDPLAYER;
1642 /* Remove the player shortcut from the group */
1643 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1645 if( lpPList == NULL )
1647 return DPERR_INVALIDPLAYER;
1650 /* One less reference */
1651 lpPList->lpPData->uRef--;
1653 /* Delete the Player List element */
1654 HeapFree( GetProcessHeap(), 0, lpPList );
1656 /* Inform the SP if they care */
1657 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1659 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1661 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1663 data.idPlayer = idPlayer;
1664 data.idGroup = idGroup;
1665 data.lpISP = This->dp2->spData.lpISP;
1667 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1670 /* Need to send a DELETEPLAYERFROMGROUP message */
1671 FIXME( "Need to send a message\n" );
1673 return hr;
1676 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1677 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1679 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1680 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1683 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1684 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1686 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1687 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1690 typedef struct _DPRGOPContext
1692 IDirectPlay3Impl* This;
1693 BOOL bAnsi;
1694 DPID idGroup;
1695 } DPRGOPContext, *lpDPRGOPContext;
1697 static BOOL CALLBACK
1698 cbRemoveGroupOrPlayer(
1699 DPID dpId,
1700 DWORD dwPlayerType,
1701 LPCDPNAME lpName,
1702 DWORD dwFlags,
1703 LPVOID lpContext )
1705 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1707 TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1708 dpId, dwPlayerType, lpCtxt->idGroup );
1710 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1712 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1713 dpId )
1717 ERR( "Unable to delete group 0x%08x from group 0x%08x\n",
1718 dpId, lpCtxt->idGroup );
1721 else
1723 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1724 NULL, lpCtxt->idGroup,
1725 dpId, lpCtxt->bAnsi )
1729 ERR( "Unable to delete player 0x%08x from grp 0x%08x\n",
1730 dpId, lpCtxt->idGroup );
1734 return TRUE; /* Continue enumeration */
1737 static HRESULT DP_IF_DestroyGroup
1738 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1740 lpGroupData lpGData;
1741 DPRGOPContext context;
1743 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1744 This, lpMsgHdr, idGroup, bAnsi );
1746 /* Find the group */
1747 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1749 return DPERR_INVALIDPLAYER; /* yes player */
1752 context.This = (IDirectPlay3Impl*)This;
1753 context.bAnsi = bAnsi;
1754 context.idGroup = idGroup;
1756 /* Remove all players that this group has */
1757 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1758 cbRemoveGroupOrPlayer, &context, 0, bAnsi );
1760 /* Remove all links to groups that this group has since this is dp3 */
1761 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1762 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1764 /* Remove this group from the parent group - if it has one */
1765 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1766 ( lpGData->parent != DPID_SYSTEM_GROUP )
1769 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1770 idGroup );
1773 /* Now delete this group data and list from the system group */
1774 DP_DeleteGroup( This, idGroup );
1776 /* Let the SP know that we've destroyed this group */
1777 if( This->dp2->spData.lpCB->DeleteGroup )
1779 DPSP_DELETEGROUPDATA data;
1781 FIXME( "data.dwFlags is incorrect\n" );
1783 data.idGroup = idGroup;
1784 data.dwFlags = 0;
1785 data.lpISP = This->dp2->spData.lpISP;
1787 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1790 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1792 return DP_OK;
1795 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1796 ( LPDIRECTPLAY2A iface, DPID idGroup )
1798 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1799 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1802 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1803 ( LPDIRECTPLAY2 iface, DPID idGroup )
1805 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1806 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1809 typedef struct _DPFAGContext
1811 IDirectPlay2Impl* This;
1812 DPID idPlayer;
1813 BOOL bAnsi;
1814 } DPFAGContext, *lpDPFAGContext;
1816 static HRESULT DP_IF_DestroyPlayer
1817 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1819 DPFAGContext cbContext;
1821 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1822 This, lpMsgHdr, idPlayer, bAnsi );
1824 if( This->dp2->connectionInitialized == NO_PROVIDER )
1826 return DPERR_UNINITIALIZED;
1829 if( DP_FindPlayer( This, idPlayer ) == NULL )
1831 return DPERR_INVALIDPLAYER;
1834 /* FIXME: If the player is remote, we must be the host to delete this */
1836 cbContext.This = This;
1837 cbContext.idPlayer = idPlayer;
1838 cbContext.bAnsi = bAnsi;
1840 /* Find each group and call DeletePlayerFromGroup if the player is a
1841 member of the group */
1842 DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
1843 &cbContext, DPENUMGROUPS_ALL, bAnsi );
1845 /* Now delete player and player list from the sys group */
1846 DP_DeletePlayer( This, idPlayer );
1848 /* Let the SP know that we've destroyed this group */
1849 if( This->dp2->spData.lpCB->DeletePlayer )
1851 DPSP_DELETEPLAYERDATA data;
1853 FIXME( "data.dwFlags is incorrect\n" );
1855 data.idPlayer = idPlayer;
1856 data.dwFlags = 0;
1857 data.lpISP = This->dp2->spData.lpISP;
1859 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1862 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1864 return DP_OK;
1867 static BOOL CALLBACK
1868 cbDeletePlayerFromAllGroups(
1869 DPID dpId,
1870 DWORD dwPlayerType,
1871 LPCDPNAME lpName,
1872 DWORD dwFlags,
1873 LPVOID lpContext )
1875 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1877 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1879 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
1880 lpCtxt->bAnsi );
1882 /* Enumerate all groups in this group since this will normally only
1883 * be called for top level groups
1885 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
1886 dpId, NULL,
1887 cbDeletePlayerFromAllGroups,
1888 lpContext, DPENUMGROUPS_ALL,
1889 lpCtxt->bAnsi );
1892 else
1894 ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
1897 return TRUE;
1900 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
1901 ( LPDIRECTPLAY2A iface, DPID idPlayer )
1903 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1904 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1907 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1908 ( LPDIRECTPLAY2 iface, DPID idPlayer )
1910 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1911 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1914 static HRESULT DP_IF_EnumGroupPlayers
1915 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1916 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1917 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1919 lpGroupData lpGData;
1920 lpPlayerList lpPList;
1922 FIXME("(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
1923 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1924 lpContext, dwFlags, bAnsi );
1926 if( This->dp2->connectionInitialized == NO_PROVIDER )
1928 return DPERR_UNINITIALIZED;
1931 /* Find the group */
1932 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1934 return DPERR_INVALIDGROUP;
1937 if( DPQ_IS_EMPTY( lpGData->players ) )
1939 return DP_OK;
1942 lpPList = DPQ_FIRST( lpGData->players );
1944 /* Walk the players in this group */
1945 for( ;; )
1947 /* We do not enum the name server or app server as they are of no
1948 * consequence to the end user.
1950 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
1951 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
1955 /* FIXME: Need to add stuff for dwFlags checking */
1957 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1958 &lpPList->lpPData->name,
1959 lpPList->lpPData->dwFlags,
1960 lpContext )
1963 /* User requested break */
1964 return DP_OK;
1968 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
1970 break;
1973 lpPList = DPQ_NEXT( lpPList->players );
1976 return DP_OK;
1979 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
1980 ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
1981 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1982 LPVOID lpContext, DWORD dwFlags )
1984 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1985 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
1986 lpEnumPlayersCallback2, lpContext,
1987 dwFlags, TRUE );
1990 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
1991 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
1992 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1993 LPVOID lpContext, DWORD dwFlags )
1995 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1996 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
1997 lpEnumPlayersCallback2, lpContext,
1998 dwFlags, FALSE );
2001 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2002 static HRESULT DP_IF_EnumGroups
2003 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2004 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2005 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2007 return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2008 DPID_SYSTEM_GROUP, lpguidInstance,
2009 lpEnumPlayersCallback2, lpContext,
2010 dwFlags, bAnsi );
2013 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2014 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2015 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2016 LPVOID lpContext, DWORD dwFlags )
2018 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2019 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2020 lpContext, dwFlags, TRUE );
2023 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2024 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2025 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2026 LPVOID lpContext, DWORD dwFlags )
2028 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2029 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2030 lpContext, dwFlags, FALSE );
2033 static HRESULT DP_IF_EnumPlayers
2034 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2035 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2036 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2038 return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
2039 lpEnumPlayersCallback2, lpContext,
2040 dwFlags, bAnsi );
2043 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2044 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2045 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2046 LPVOID lpContext, DWORD dwFlags )
2048 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2049 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2050 lpContext, dwFlags, TRUE );
2053 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2054 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2055 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2056 LPVOID lpContext, DWORD dwFlags )
2058 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2059 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2060 lpContext, dwFlags, FALSE );
2063 /* This function should call the registered callback function that the user
2064 passed into EnumSessions for each entry available.
2066 static void DP_InvokeEnumSessionCallbacks
2067 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2068 LPVOID lpNSInfo,
2069 DWORD dwTimeout,
2070 LPVOID lpContext )
2072 LPDPSESSIONDESC2 lpSessionDesc;
2074 FIXME( ": not checking for conditions\n" );
2076 /* Not sure if this should be pruning but it's convenient */
2077 NS_PruneSessionCache( lpNSInfo );
2079 NS_ResetSessionEnumeration( lpNSInfo );
2081 /* Enumerate all sessions */
2082 /* FIXME: Need to indicate ANSI */
2083 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2085 TRACE( "EnumSessionsCallback2 invoked\n" );
2086 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2088 return;
2092 /* Invoke one last time to indicate that there is no more to come */
2093 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2096 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2098 EnumSessionAsyncCallbackData* data = lpContext;
2099 HANDLE hSuicideRequest = data->hSuicideRequest;
2100 DWORD dwTimeout = data->dwTimeout;
2102 TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
2104 for( ;; )
2106 HRESULT hr;
2108 /* Sleep up to dwTimeout waiting for request to terminate thread */
2109 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2111 TRACE( "Thread terminating on terminate request\n" );
2112 break;
2115 /* Now resend the enum request */
2116 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2117 data->dwEnumSessionFlags,
2118 data->lpSpData );
2120 if( FAILED(hr) )
2122 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2123 /* FIXME: Should we kill this thread? How to inform the main thread? */
2128 TRACE( "Thread terminating\n" );
2130 /* Clean up the thread data */
2131 CloseHandle( hSuicideRequest );
2132 HeapFree( GetProcessHeap(), 0, lpContext );
2134 /* FIXME: Need to have some notification to main app thread that this is
2135 * dead. It would serve two purposes. 1) allow sync on termination
2136 * so that we don't actually send something to ourselves when we
2137 * become name server (race condition) and 2) so that if we die
2138 * abnormally something else will be able to tell.
2141 return 1;
2144 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
2146 /* Does a thread exist? If so we were doing an async enum session */
2147 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2149 TRACE( "Killing EnumSession thread %p\n",
2150 This->dp2->hEnumSessionThread );
2152 /* Request that the thread kill itself nicely */
2153 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2154 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2156 /* We no longer need to know about the thread */
2157 CloseHandle( This->dp2->hEnumSessionThread );
2159 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2163 static HRESULT DP_IF_EnumSessions
2164 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2165 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2166 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2168 HRESULT hr = DP_OK;
2170 TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x,%u)\n",
2171 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2172 bAnsi );
2173 if( This->dp2->connectionInitialized == NO_PROVIDER )
2175 return DPERR_UNINITIALIZED;
2178 /* Can't enumerate if the interface is already open */
2179 if( This->dp2->bConnectionOpen )
2181 return DPERR_GENERIC;
2184 #if 1
2185 /* The loading of a lobby provider _seems_ to require a backdoor loading
2186 * of the service provider to also associate with this DP object. This is
2187 * because the app doesn't seem to have to call EnumConnections and
2188 * InitializeConnection for the SP before calling this method. As such
2189 * we'll do their dirty work for them with a quick hack so as to always
2190 * load the TCP/IP service provider.
2192 * The correct solution would seem to involve creating a dialog box which
2193 * contains the possible SPs. These dialog boxes most likely follow SDK
2194 * examples.
2196 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2198 LPVOID lpConnection;
2199 DWORD dwSize;
2201 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2203 if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2205 ERR( "Can't build compound addr\n" );
2206 return DPERR_GENERIC;
2209 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2210 0, bAnsi );
2211 if( FAILED(hr) )
2213 return hr;
2216 /* Free up the address buffer */
2217 HeapFree( GetProcessHeap(), 0, lpConnection );
2219 /* The SP is now initialized */
2220 This->dp2->bSPInitialized = TRUE;
2222 #endif
2225 /* Use the service provider default? */
2226 if( dwTimeout == 0 )
2228 DPCAPS spCaps;
2229 spCaps.dwSize = sizeof( spCaps );
2231 DP_IF_GetCaps( This, &spCaps, 0 );
2232 dwTimeout = spCaps.dwTimeout;
2234 /* The service provider doesn't provide one either! */
2235 if( dwTimeout == 0 )
2237 /* Provide the TCP/IP default */
2238 dwTimeout = DPMSG_WAIT_5_SECS;
2242 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2244 DP_KillEnumSessionThread( This );
2245 return hr;
2248 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2250 /* Enumerate everything presently in the local session cache */
2251 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2252 This->dp2->lpNameServerData, dwTimeout,
2253 lpContext );
2255 if( This->dp2->dwEnumSessionLock != 0 )
2256 return DPERR_CONNECTING;
2258 /* See if we've already created a thread to service this interface */
2259 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2261 DWORD dwThreadId;
2262 This->dp2->dwEnumSessionLock++;
2264 /* Send the first enum request inline since the user may cancel a dialog
2265 * if one is presented. Also, may also have a connecting return code.
2267 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2268 dwFlags, &This->dp2->spData );
2270 if( SUCCEEDED(hr) )
2272 EnumSessionAsyncCallbackData* lpData
2273 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2274 /* FIXME: need to kill the thread on object deletion */
2275 lpData->lpSpData = &This->dp2->spData;
2277 lpData->requestGuid = lpsd->guidApplication;
2278 lpData->dwEnumSessionFlags = dwFlags;
2279 lpData->dwTimeout = dwTimeout;
2281 This->dp2->hKillEnumSessionThreadEvent =
2282 CreateEventW( NULL, TRUE, FALSE, NULL );
2284 if( !DuplicateHandle( GetCurrentProcess(),
2285 This->dp2->hKillEnumSessionThreadEvent,
2286 GetCurrentProcess(),
2287 &lpData->hSuicideRequest,
2288 0, FALSE, DUPLICATE_SAME_ACCESS )
2291 ERR( "Can't duplicate thread killing handle\n" );
2294 TRACE( ": creating EnumSessionsRequest thread\n" );
2296 This->dp2->hEnumSessionThread = CreateThread( NULL,
2298 DP_EnumSessionsSendAsyncRequestThread,
2299 lpData,
2301 &dwThreadId );
2303 This->dp2->dwEnumSessionLock--;
2306 else
2308 /* Invalidate the session cache for the interface */
2309 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2311 /* Send the broadcast for session enumeration */
2312 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2313 dwFlags,
2314 &This->dp2->spData );
2317 SleepEx( dwTimeout, FALSE );
2319 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2320 This->dp2->lpNameServerData, dwTimeout,
2321 lpContext );
2324 return hr;
2327 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2328 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2329 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2330 LPVOID lpContext, DWORD dwFlags )
2332 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2333 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2334 lpContext, dwFlags, TRUE );
2337 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2338 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2339 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2340 LPVOID lpContext, DWORD dwFlags )
2342 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2343 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2344 lpContext, dwFlags, FALSE );
2347 static HRESULT DP_IF_GetPlayerCaps
2348 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2349 DWORD dwFlags )
2351 DPSP_GETCAPSDATA data;
2353 TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
2355 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2357 return DPERR_UNINITIALIZED;
2360 /* Query the service provider */
2361 data.idPlayer = idPlayer;
2362 data.dwFlags = dwFlags;
2363 data.lpCaps = lpDPCaps;
2364 data.lpISP = This->dp2->spData.lpISP;
2366 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2369 static HRESULT DP_IF_GetCaps
2370 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2372 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2375 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2376 ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2378 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2379 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2382 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2383 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2385 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2386 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2389 static HRESULT DP_IF_GetGroupData
2390 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2391 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2393 lpGroupData lpGData;
2394 DWORD dwRequiredBufferSize;
2395 LPVOID lpCopyDataFrom;
2397 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2398 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2400 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2402 return DPERR_INVALIDGROUP;
2405 /* How much buffer is required? */
2406 if( dwFlags & DPSET_LOCAL )
2408 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2409 lpCopyDataFrom = lpGData->lpLocalData;
2411 else
2413 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2414 lpCopyDataFrom = lpGData->lpRemoteData;
2417 /* Is the user requesting to know how big a buffer is required? */
2418 if( ( lpData == NULL ) ||
2419 ( *lpdwDataSize < dwRequiredBufferSize )
2422 *lpdwDataSize = dwRequiredBufferSize;
2423 return DPERR_BUFFERTOOSMALL;
2426 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2428 return DP_OK;
2431 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2432 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2433 LPDWORD lpdwDataSize, DWORD dwFlags )
2435 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2436 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2437 dwFlags, TRUE );
2440 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2441 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2442 LPDWORD lpdwDataSize, DWORD dwFlags )
2444 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2445 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2446 dwFlags, FALSE );
2449 static HRESULT DP_IF_GetGroupName
2450 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2451 LPDWORD lpdwDataSize, BOOL bAnsi )
2453 lpGroupData lpGData;
2454 LPDPNAME lpName = lpData;
2455 DWORD dwRequiredDataSize;
2457 FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2458 This, idGroup, lpData, lpdwDataSize, bAnsi );
2460 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2462 return DPERR_INVALIDGROUP;
2465 dwRequiredDataSize = lpGData->name.dwSize;
2467 if( lpGData->name.u1.lpszShortNameA )
2469 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2472 if( lpGData->name.u2.lpszLongNameA )
2474 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2477 if( ( lpData == NULL ) ||
2478 ( *lpdwDataSize < dwRequiredDataSize )
2481 *lpdwDataSize = dwRequiredDataSize;
2482 return DPERR_BUFFERTOOSMALL;
2485 /* Copy the structure */
2486 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2488 if( lpGData->name.u1.lpszShortNameA )
2490 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2491 lpGData->name.u1.lpszShortNameA );
2493 else
2495 lpName->u1.lpszShortNameA = NULL;
2498 if( lpGData->name.u1.lpszShortNameA )
2500 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2501 lpGData->name.u2.lpszLongNameA );
2503 else
2505 lpName->u2.lpszLongNameA = NULL;
2508 return DP_OK;
2511 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2512 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2513 LPDWORD lpdwDataSize )
2515 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2516 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2519 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2520 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2521 LPDWORD lpdwDataSize )
2523 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2524 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2527 static HRESULT DP_IF_GetMessageCount
2528 ( IDirectPlay2Impl* This, DPID idPlayer,
2529 LPDWORD lpdwCount, BOOL bAnsi )
2531 FIXME("(%p)->(0x%08x,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2532 return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2533 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2534 bAnsi );
2537 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2538 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2540 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2541 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2544 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2545 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2547 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2548 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2551 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2552 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2554 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2555 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2556 return DP_OK;
2559 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2560 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2562 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2563 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2564 return DP_OK;
2567 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2568 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2569 DWORD dwFlags )
2571 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2572 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2575 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2576 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2577 DWORD dwFlags )
2579 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2580 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2583 static HRESULT DP_IF_GetPlayerData
2584 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2585 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2587 lpPlayerList lpPList;
2588 DWORD dwRequiredBufferSize;
2589 LPVOID lpCopyDataFrom;
2591 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2592 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2594 if( This->dp2->connectionInitialized == NO_PROVIDER )
2596 return DPERR_UNINITIALIZED;
2599 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2601 return DPERR_INVALIDPLAYER;
2604 /* How much buffer is required? */
2605 if( dwFlags & DPSET_LOCAL )
2607 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2608 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2610 else
2612 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2613 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2616 /* Is the user requesting to know how big a buffer is required? */
2617 if( ( lpData == NULL ) ||
2618 ( *lpdwDataSize < dwRequiredBufferSize )
2621 *lpdwDataSize = dwRequiredBufferSize;
2622 return DPERR_BUFFERTOOSMALL;
2625 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2627 return DP_OK;
2630 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2631 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2632 LPDWORD lpdwDataSize, DWORD dwFlags )
2634 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2635 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2636 dwFlags, TRUE );
2639 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2640 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2641 LPDWORD lpdwDataSize, DWORD dwFlags )
2643 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2644 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2645 dwFlags, FALSE );
2648 static HRESULT DP_IF_GetPlayerName
2649 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2650 LPDWORD lpdwDataSize, BOOL bAnsi )
2652 lpPlayerList lpPList;
2653 LPDPNAME lpName = lpData;
2654 DWORD dwRequiredDataSize;
2656 FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2657 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2659 if( This->dp2->connectionInitialized == NO_PROVIDER )
2661 return DPERR_UNINITIALIZED;
2664 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2666 return DPERR_INVALIDPLAYER;
2669 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2671 if( lpPList->lpPData->name.u1.lpszShortNameA )
2673 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2676 if( lpPList->lpPData->name.u2.lpszLongNameA )
2678 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2681 if( ( lpData == NULL ) ||
2682 ( *lpdwDataSize < dwRequiredDataSize )
2685 *lpdwDataSize = dwRequiredDataSize;
2686 return DPERR_BUFFERTOOSMALL;
2689 /* Copy the structure */
2690 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2692 if( lpPList->lpPData->name.u1.lpszShortNameA )
2694 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2695 lpPList->lpPData->name.u1.lpszShortNameA );
2697 else
2699 lpName->u1.lpszShortNameA = NULL;
2702 if( lpPList->lpPData->name.u1.lpszShortNameA )
2704 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2705 lpPList->lpPData->name.u2.lpszLongNameA );
2707 else
2709 lpName->u2.lpszLongNameA = NULL;
2712 return DP_OK;
2715 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2716 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2717 LPDWORD lpdwDataSize )
2719 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2720 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2723 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2724 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2725 LPDWORD lpdwDataSize )
2727 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2728 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2731 static HRESULT DP_GetSessionDesc
2732 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2733 BOOL bAnsi )
2735 DWORD dwRequiredSize;
2737 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2739 if( This->dp2->connectionInitialized == NO_PROVIDER )
2741 return DPERR_UNINITIALIZED;
2744 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2746 return DPERR_INVALIDPARAMS;
2749 /* FIXME: Get from This->dp2->lpSessionDesc */
2750 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2752 if ( ( lpData == NULL ) ||
2753 ( *lpdwDataSize < dwRequiredSize )
2756 *lpdwDataSize = dwRequiredSize;
2757 return DPERR_BUFFERTOOSMALL;
2760 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2762 return DP_OK;
2765 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2766 ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2768 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2769 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2772 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2773 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2775 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2776 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2779 /* Intended only for COM compatibility. Always returns an error. */
2780 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2781 ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2783 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2784 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2785 return DPERR_ALREADYINITIALIZED;
2788 /* Intended only for COM compatibility. Always returns an error. */
2789 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2790 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2792 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2793 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2794 return DPERR_ALREADYINITIALIZED;
2798 static HRESULT DP_SecureOpen
2799 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2800 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2801 BOOL bAnsi )
2803 HRESULT hr = DP_OK;
2805 FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2806 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2808 if( This->dp2->connectionInitialized == NO_PROVIDER )
2810 return DPERR_UNINITIALIZED;
2813 if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
2815 TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
2816 return DPERR_INVALIDPARAMS;
2819 if( This->dp2->bConnectionOpen )
2821 TRACE( ": rejecting already open connection.\n" );
2822 return DPERR_ALREADYINITIALIZED;
2825 /* If we're enumerating, kill the thread */
2826 DP_KillEnumSessionThread( This );
2828 if( dwFlags & DPOPEN_CREATE )
2830 /* Rightoo - this computer is the host and the local computer needs to be
2831 the name server so that others can join this session */
2832 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2834 This->dp2->bHostInterface = TRUE;
2836 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2837 if( FAILED( hr ) )
2839 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2840 return hr;
2844 /* Invoke the conditional callback for the service provider */
2845 if( This->dp2->spData.lpCB->Open )
2847 DPSP_OPENDATA data;
2849 FIXME( "Not all data fields are correct. Need new parameter\n" );
2851 data.bCreate = (dwFlags & DPOPEN_CREATE ) != 0;
2852 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2853 : NS_GetNSAddr( This->dp2->lpNameServerData );
2854 data.lpISP = This->dp2->spData.lpISP;
2855 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) != 0;
2856 data.dwOpenFlags = dwFlags;
2857 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2859 hr = (*This->dp2->spData.lpCB->Open)(&data);
2860 if( FAILED( hr ) )
2862 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2863 return hr;
2868 /* Create the system group of which everything is a part of */
2869 DPID systemGroup = DPID_SYSTEM_GROUP;
2871 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2872 NULL, 0, 0, TRUE );
2876 if( dwFlags & DPOPEN_JOIN )
2878 DPID dpidServerId = DPID_UNKNOWN;
2880 /* Create the server player for this interface. This way we can receive
2881 * messages for this session.
2883 /* FIXME: I suppose that we should be setting an event for a receive
2884 * type of thing. That way the messaging thread could know to wake
2885 * up. DPlay would then trigger the hEvent for the player the
2886 * message is directed to.
2888 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2890 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2893 else if( dwFlags & DPOPEN_CREATE )
2895 DPID dpidNameServerId = DPID_NAME_SERVER;
2897 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2898 0, DPPLAYER_SERVERPLAYER, bAnsi );
2901 if( FAILED(hr) )
2903 ERR( "Couldn't create name server/system player: %s\n",
2904 DPLAYX_HresultToString(hr) );
2907 return hr;
2910 static HRESULT WINAPI DirectPlay2AImpl_Open
2911 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2913 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2914 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2915 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
2918 static HRESULT WINAPI DirectPlay2WImpl_Open
2919 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2921 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2922 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2923 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
2926 static HRESULT DP_IF_Receive
2927 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2928 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2930 LPDPMSG lpMsg = NULL;
2932 FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
2933 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2935 if( This->dp2->connectionInitialized == NO_PROVIDER )
2937 return DPERR_UNINITIALIZED;
2940 if( dwFlags == 0 )
2942 dwFlags = DPRECEIVE_ALL;
2945 /* If the lpData is NULL, we must be peeking the message */
2946 if( ( lpData == NULL ) &&
2947 !( dwFlags & DPRECEIVE_PEEK )
2950 return DPERR_INVALIDPARAMS;
2953 if( dwFlags & DPRECEIVE_ALL )
2955 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2957 if( !( dwFlags & DPRECEIVE_PEEK ) )
2959 FIXME( "Remove from queue\n" );
2962 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2963 ( dwFlags & DPRECEIVE_FROMPLAYER )
2966 FIXME( "Find matching message 0x%08x\n", dwFlags );
2968 else
2970 ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
2973 if( lpMsg == NULL )
2975 return DPERR_NOMESSAGES;
2978 /* Copy into the provided buffer */
2979 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
2981 return DP_OK;
2984 static HRESULT WINAPI DirectPlay2AImpl_Receive
2985 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
2986 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2988 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2989 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2990 lpData, lpdwDataSize, TRUE );
2993 static HRESULT WINAPI DirectPlay2WImpl_Receive
2994 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
2995 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2997 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2998 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2999 lpData, lpdwDataSize, FALSE );
3002 static HRESULT WINAPI DirectPlay2AImpl_Send
3003 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3005 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3006 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3007 0, 0, NULL, NULL, TRUE );
3010 static HRESULT WINAPI DirectPlay2WImpl_Send
3011 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3013 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3014 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3015 0, 0, NULL, NULL, FALSE );
3018 static HRESULT DP_IF_SetGroupData
3019 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3020 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3022 lpGroupData lpGData;
3024 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3025 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3027 /* Parameter check */
3028 if( ( lpData == NULL ) &&
3029 ( dwDataSize != 0 )
3032 return DPERR_INVALIDPARAMS;
3035 /* Find the pointer to the data for this player */
3036 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3038 return DPERR_INVALIDOBJECT;
3041 if( !(dwFlags & DPSET_LOCAL) )
3043 FIXME( "Was this group created by this interface?\n" );
3044 /* FIXME: If this is a remote update need to allow it but not
3045 * send a message.
3049 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3051 /* FIXME: Only send a message if this group is local to the session otherwise
3052 * it will have been rejected above
3054 if( !(dwFlags & DPSET_LOCAL) )
3056 FIXME( "Send msg?\n" );
3059 return DP_OK;
3062 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3063 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3064 DWORD dwDataSize, DWORD dwFlags )
3066 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3067 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3070 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3071 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3072 DWORD dwDataSize, DWORD dwFlags )
3074 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3075 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3078 static HRESULT DP_IF_SetGroupName
3079 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3080 DWORD dwFlags, BOOL bAnsi )
3082 lpGroupData lpGData;
3084 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3085 lpGroupName, dwFlags, bAnsi );
3087 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3089 return DPERR_INVALIDGROUP;
3092 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3094 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3095 FIXME( "Message not sent and dwFlags ignored\n" );
3097 return DP_OK;
3100 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3101 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3102 DWORD dwFlags )
3104 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3105 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3108 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3109 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3110 DWORD dwFlags )
3112 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3113 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3116 static HRESULT DP_IF_SetPlayerData
3117 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3118 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3120 lpPlayerList lpPList;
3122 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3123 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3125 if( This->dp2->connectionInitialized == NO_PROVIDER )
3127 return DPERR_UNINITIALIZED;
3130 /* Parameter check */
3131 if( ( lpData == NULL ) &&
3132 ( dwDataSize != 0 )
3135 return DPERR_INVALIDPARAMS;
3138 /* Find the pointer to the data for this player */
3139 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3141 return DPERR_INVALIDPLAYER;
3144 if( !(dwFlags & DPSET_LOCAL) )
3146 FIXME( "Was this group created by this interface?\n" );
3147 /* FIXME: If this is a remote update need to allow it but not
3148 * send a message.
3152 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3154 if( !(dwFlags & DPSET_LOCAL) )
3156 FIXME( "Send msg?\n" );
3159 return DP_OK;
3162 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3163 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3164 DWORD dwDataSize, DWORD dwFlags )
3166 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3167 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3168 dwFlags, TRUE );
3171 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3172 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3173 DWORD dwDataSize, DWORD dwFlags )
3175 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3176 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3177 dwFlags, FALSE );
3180 static HRESULT DP_IF_SetPlayerName
3181 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3182 DWORD dwFlags, BOOL bAnsi )
3184 lpPlayerList lpPList;
3186 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3187 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3189 if( This->dp2->connectionInitialized == NO_PROVIDER )
3191 return DPERR_UNINITIALIZED;
3194 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3196 return DPERR_INVALIDGROUP;
3199 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3201 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3202 FIXME( "Message not sent and dwFlags ignored\n" );
3204 return DP_OK;
3207 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3208 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3209 DWORD dwFlags )
3211 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3212 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3215 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3216 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3217 DWORD dwFlags )
3219 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3220 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3223 static HRESULT DP_SetSessionDesc
3224 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3225 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3227 DWORD dwRequiredSize;
3228 LPDPSESSIONDESC2 lpTempSessDesc;
3230 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3231 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3233 if( This->dp2->connectionInitialized == NO_PROVIDER )
3235 return DPERR_UNINITIALIZED;
3238 if( dwFlags )
3240 return DPERR_INVALIDPARAMS;
3243 /* Only the host is allowed to update the session desc */
3244 if( !This->dp2->bHostInterface )
3246 return DPERR_ACCESSDENIED;
3249 /* FIXME: Copy into This->dp2->lpSessionDesc */
3250 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3251 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3253 if( lpTempSessDesc == NULL )
3255 return DPERR_OUTOFMEMORY;
3258 /* Free the old */
3259 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3261 This->dp2->lpSessionDesc = lpTempSessDesc;
3262 /* Set the new */
3263 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3264 if( bInitial )
3266 /*Initializing session GUID*/
3267 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3269 /* If this is an external invocation of the interface, we should be
3270 * letting everyone know that things have changed. Otherwise this is
3271 * just an initialization and it doesn't need to be propagated.
3273 if( !bInitial )
3275 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3278 return DP_OK;
3281 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3282 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3284 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3285 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3288 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3289 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3291 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3292 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3295 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3296 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3298 DWORD dwSize = 0;
3300 if( lpSessDesc == NULL )
3302 /* Hmmm..don't need any size? */
3303 ERR( "NULL lpSessDesc\n" );
3304 return dwSize;
3307 dwSize += sizeof( *lpSessDesc );
3309 if( bAnsi )
3311 if( lpSessDesc->u1.lpszSessionNameA )
3313 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3316 if( lpSessDesc->u2.lpszPasswordA )
3318 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3321 else /* UNICODE */
3323 if( lpSessDesc->u1.lpszSessionName )
3325 dwSize += sizeof( WCHAR ) *
3326 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3329 if( lpSessDesc->u2.lpszPassword )
3331 dwSize += sizeof( WCHAR ) *
3332 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3336 return dwSize;
3339 /* Assumes that contiguous buffers are already allocated. */
3340 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3341 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3343 BYTE* lpStartOfFreeSpace;
3345 if( lpSessionDest == NULL )
3347 ERR( "NULL lpSessionDest\n" );
3348 return;
3351 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3353 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3355 if( bAnsi )
3357 if( lpSessionSrc->u1.lpszSessionNameA )
3359 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3360 lpSessionDest->u1.lpszSessionNameA );
3361 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3362 lpStartOfFreeSpace +=
3363 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3366 if( lpSessionSrc->u2.lpszPasswordA )
3368 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3369 lpSessionDest->u2.lpszPasswordA );
3370 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3373 else /* UNICODE */
3375 if( lpSessionSrc->u1.lpszSessionName )
3377 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3378 lpSessionDest->u1.lpszSessionName );
3379 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3380 lpStartOfFreeSpace += sizeof(WCHAR) *
3381 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3384 if( lpSessionSrc->u2.lpszPassword )
3386 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3387 lpSessionDest->u2.lpszPassword );
3388 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3394 static HRESULT DP_IF_AddGroupToGroup
3395 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3397 lpGroupData lpGData;
3398 lpGroupList lpNewGList;
3400 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3402 if( This->dp2->connectionInitialized == NO_PROVIDER )
3404 return DPERR_UNINITIALIZED;
3407 if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3409 return DPERR_INVALIDGROUP;
3412 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3414 return DPERR_INVALIDGROUP;
3417 /* Create a player list (ie "shortcut" ) */
3418 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3419 if( lpNewGList == NULL )
3421 return DPERR_CANTADDPLAYER;
3424 /* Add the shortcut */
3425 lpGData->uRef++;
3426 lpNewGList->lpGData = lpGData;
3428 /* Add the player to the list of players for this group */
3429 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3431 /* Send a ADDGROUPTOGROUP message */
3432 FIXME( "Not sending message\n" );
3434 return DP_OK;
3437 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3438 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3440 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3441 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3444 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3445 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3447 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3448 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3451 static HRESULT DP_IF_CreateGroupInGroup
3452 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3453 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3454 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3456 lpGroupData lpGParentData;
3457 lpGroupList lpGList;
3458 lpGroupData lpGData;
3460 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3461 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3462 dwDataSize, dwFlags, bAnsi );
3464 if( This->dp2->connectionInitialized == NO_PROVIDER )
3466 return DPERR_UNINITIALIZED;
3469 /* Verify that the specified parent is valid */
3470 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3471 idParentGroup ) ) == NULL
3474 return DPERR_INVALIDGROUP;
3477 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3478 dwFlags, idParentGroup, bAnsi );
3480 if( lpGData == NULL )
3482 return DPERR_CANTADDPLAYER; /* yes player not group */
3485 /* Something else is referencing this data */
3486 lpGData->uRef++;
3488 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3490 /* The list has now been inserted into the interface group list. We now
3491 need to put a "shortcut" to this group in the parent group */
3492 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3493 if( lpGList == NULL )
3495 FIXME( "Memory leak\n" );
3496 return DPERR_CANTADDPLAYER; /* yes player not group */
3499 lpGList->lpGData = lpGData;
3501 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3503 /* Let the SP know that we've created this group */
3504 if( This->dp2->spData.lpCB->CreateGroup )
3506 DPSP_CREATEGROUPDATA data;
3508 TRACE( "Calling SP CreateGroup\n" );
3510 data.idGroup = *lpidGroup;
3511 data.dwFlags = dwFlags;
3512 data.lpSPMessageHeader = lpMsgHdr;
3513 data.lpISP = This->dp2->spData.lpISP;
3515 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3518 /* Inform all other peers of the creation of a new group. If there are
3519 * no peers keep this quiet.
3521 if( This->dp2->lpSessionDesc &&
3522 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3524 DPMSG_CREATEPLAYERORGROUP msg;
3526 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3527 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3528 msg.dpId = *lpidGroup;
3529 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3530 msg.lpData = lpData;
3531 msg.dwDataSize = dwDataSize;
3532 msg.dpnName = *lpGroupName;
3534 /* FIXME: Correct to just use send effectively? */
3535 /* FIXME: Should size include data w/ message or just message "header" */
3536 /* FIXME: Check return code */
3537 DP_SendEx( (IDirectPlay2Impl*)This,
3538 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3539 0, 0, NULL, NULL, bAnsi );
3542 return DP_OK;
3545 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3546 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3547 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3548 DWORD dwFlags )
3550 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3552 *lpidGroup = DPID_UNKNOWN;
3554 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3555 lpGroupName, lpData, dwDataSize, dwFlags,
3556 TRUE );
3559 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3560 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3561 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3562 DWORD dwFlags )
3564 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3566 *lpidGroup = DPID_UNKNOWN;
3568 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3569 lpGroupName, lpData, dwDataSize,
3570 dwFlags, FALSE );
3573 static HRESULT DP_IF_DeleteGroupFromGroup
3574 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3576 lpGroupList lpGList;
3577 lpGroupData lpGParentData;
3579 TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3581 /* Is the parent group valid? */
3582 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3584 return DPERR_INVALIDGROUP;
3587 /* Remove the group from the parent group queue */
3588 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3590 if( lpGList == NULL )
3592 return DPERR_INVALIDGROUP;
3595 /* Decrement the ref count */
3596 lpGList->lpGData->uRef--;
3598 /* Free up the list item */
3599 HeapFree( GetProcessHeap(), 0, lpGList );
3601 /* Should send a DELETEGROUPFROMGROUP message */
3602 FIXME( "message not sent\n" );
3604 return DP_OK;
3607 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3608 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3610 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3611 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3614 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3615 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3617 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3618 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3621 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3622 LPDWORD lpdwBufSize )
3624 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3625 HRESULT hr;
3627 dpCompoundAddress.dwDataSize = sizeof( GUID );
3628 dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3629 dpCompoundAddress.lpData = lpcSpGuid;
3631 *lplpAddrBuf = NULL;
3632 *lpdwBufSize = 0;
3634 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3635 lpdwBufSize, TRUE );
3637 if( hr != DPERR_BUFFERTOOSMALL )
3639 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3640 return FALSE;
3643 /* Now allocate the buffer */
3644 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3645 *lpdwBufSize );
3647 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3648 lpdwBufSize, TRUE );
3649 if( FAILED(hr) )
3651 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3652 return FALSE;
3655 return TRUE;
3658 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
3659 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3661 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3662 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3664 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3665 if( dwFlags == 0 )
3667 dwFlags = DPCONNECTION_DIRECTPLAY;
3670 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3671 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3674 return DPERR_INVALIDFLAGS;
3677 if( !lpEnumCallback )
3679 return DPERR_INVALIDPARAMS;
3682 /* Enumerate DirectPlay service providers */
3683 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3685 HKEY hkResult;
3686 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3687 LPCSTR guidDataSubKey = "Guid";
3688 char subKeyName[51];
3689 DWORD dwIndex, sizeOfSubKeyName=50;
3690 FILETIME filetime;
3692 /* Need to loop over the service providers in the registry */
3693 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3694 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3696 /* Hmmm. Does this mean that there are no service providers? */
3697 ERR(": no service providers?\n");
3698 return DP_OK;
3702 /* Traverse all the service providers we have available */
3703 for( dwIndex=0;
3704 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3705 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3706 ++dwIndex, sizeOfSubKeyName=51 )
3709 HKEY hkServiceProvider;
3710 GUID serviceProviderGUID;
3711 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3712 char returnBuffer[51];
3713 WCHAR buff[51];
3714 DPNAME dpName;
3715 BOOL bBuildPass;
3717 LPVOID lpAddressBuffer = NULL;
3718 DWORD dwAddressBufferSize = 0;
3720 TRACE(" this time through: %s\n", subKeyName );
3722 /* Get a handle for this particular service provider */
3723 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3724 &hkServiceProvider ) != ERROR_SUCCESS )
3726 ERR(": what the heck is going on?\n" );
3727 continue;
3730 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3731 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3732 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3734 ERR(": missing GUID registry data members\n" );
3735 RegCloseKey(hkServiceProvider);
3736 continue;
3738 RegCloseKey(hkServiceProvider);
3740 /* FIXME: Check return types to ensure we're interpreting data right */
3741 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3742 CLSIDFromString( buff, &serviceProviderGUID );
3743 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3745 /* Fill in the DPNAME struct for the service provider */
3746 dpName.dwSize = sizeof( dpName );
3747 dpName.dwFlags = 0;
3748 dpName.u1.lpszShortNameA = subKeyName;
3749 dpName.u2.lpszLongNameA = NULL;
3751 /* Create the compound address for the service provider.
3752 * NOTE: This is a gruesome architectural scar right now. DP
3753 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3754 * native dll just gets around this little bit by allocating an
3755 * 80 byte buffer which isn't even filled with a valid compound
3756 * address. Oh well. Creating a proper compound address is the
3757 * way to go anyways despite this method taking slightly more
3758 * heap space and realtime :) */
3760 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3761 &lpAddressBuffer,
3762 &dwAddressBufferSize );
3763 if( !bBuildPass )
3765 ERR( "Can't build compound addr\n" );
3766 return DPERR_GENERIC;
3769 /* The enumeration will return FALSE if we are not to continue */
3770 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3771 &dpName, dwFlags, lpContext ) )
3773 return DP_OK;
3778 /* Enumerate DirectPlayLobby service providers */
3779 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3781 HKEY hkResult;
3782 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3783 LPCSTR guidDataSubKey = "Guid";
3784 char subKeyName[51];
3785 DWORD dwIndex, sizeOfSubKeyName=50;
3786 FILETIME filetime;
3788 /* Need to loop over the service providers in the registry */
3789 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3790 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3792 /* Hmmm. Does this mean that there are no service providers? */
3793 ERR(": no service providers?\n");
3794 return DP_OK;
3798 /* Traverse all the lobby providers we have available */
3799 for( dwIndex=0;
3800 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3801 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3802 ++dwIndex, sizeOfSubKeyName=51 )
3805 HKEY hkServiceProvider;
3806 GUID serviceProviderGUID;
3807 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3808 char returnBuffer[51];
3809 WCHAR buff[51];
3810 DPNAME dpName;
3811 HRESULT hr;
3813 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3814 LPVOID lpAddressBuffer = NULL;
3815 DWORD dwAddressBufferSize = 0;
3817 TRACE(" this time through: %s\n", subKeyName );
3819 /* Get a handle for this particular service provider */
3820 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3821 &hkServiceProvider ) != ERROR_SUCCESS )
3823 ERR(": what the heck is going on?\n" );
3824 continue;
3827 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3828 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3829 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3831 ERR(": missing GUID registry data members\n" );
3832 RegCloseKey(hkServiceProvider);
3833 continue;
3835 RegCloseKey(hkServiceProvider);
3837 /* FIXME: Check return types to ensure we're interpreting data right */
3838 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3839 CLSIDFromString( buff, &serviceProviderGUID );
3840 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3842 /* Fill in the DPNAME struct for the service provider */
3843 dpName.dwSize = sizeof( dpName );
3844 dpName.dwFlags = 0;
3845 dpName.u1.lpszShortNameA = subKeyName;
3846 dpName.u2.lpszLongNameA = NULL;
3848 /* Create the compound address for the service provider.
3849 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3850 nast stuff. This may be why the native dll just gets around this little bit by
3851 allocating an 80 byte buffer which isn't even a filled with a valid compound
3852 address. Oh well. Creating a proper compound address is the way to go anyways
3853 despite this method taking slightly more heap space and realtime :) */
3855 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3856 dpCompoundAddress.dwDataSize = sizeof( GUID );
3857 dpCompoundAddress.lpData = &serviceProviderGUID;
3859 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3860 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3862 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3863 return hr;
3866 /* Now allocate the buffer */
3867 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3869 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3870 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3872 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3873 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3874 return hr;
3877 /* The enumeration will return FALSE if we are not to continue */
3878 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3879 &dpName, dwFlags, lpContext ) )
3881 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3882 return DP_OK;
3884 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3888 return DP_OK;
3891 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3892 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3894 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3895 FIXME("(%p)->(%p,%p,%p,0x%08x): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3896 return DP_OK;
3899 static HRESULT DP_IF_EnumGroupsInGroup
3900 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3901 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3902 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3904 lpGroupList lpGList;
3905 lpGroupData lpGData;
3907 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
3908 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3909 lpContext, dwFlags, bAnsi );
3911 if( This->dp2->connectionInitialized == NO_PROVIDER )
3913 return DPERR_UNINITIALIZED;
3916 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3918 return DPERR_INVALIDGROUP;
3921 if( DPQ_IS_EMPTY( lpGData->groups ) )
3923 return DP_OK;
3926 lpGList = DPQ_FIRST( lpGData->groups );
3928 for( ;; )
3930 /* FIXME: Should check dwFlags for match here */
3932 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3933 &lpGList->lpGData->name, dwFlags,
3934 lpContext ) )
3936 return DP_OK; /* User requested break */
3939 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3941 break;
3944 lpGList = DPQ_NEXT( lpGList->groups );
3948 return DP_OK;
3951 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
3952 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3953 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3954 DWORD dwFlags )
3956 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3957 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3958 lpEnumPlayersCallback2, lpContext, dwFlags,
3959 TRUE );
3962 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3963 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3964 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3965 DWORD dwFlags )
3967 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3968 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3969 lpEnumPlayersCallback2, lpContext, dwFlags,
3970 FALSE );
3973 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
3974 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3976 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3977 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3978 return DP_OK;
3981 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
3982 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3984 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3985 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3986 return DP_OK;
3989 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
3990 REFGUID guidDataType,
3991 DWORD dwDataSize,
3992 LPCVOID lpData,
3993 LPVOID lpContext )
3995 /* Looking for the GUID of the provider to load */
3996 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
3997 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
4000 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4001 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
4003 if( dwDataSize != sizeof( GUID ) )
4005 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4008 memcpy( lpContext, lpData, dwDataSize );
4010 /* There shouldn't be more than 1 GUID/compound address */
4011 return FALSE;
4014 /* Still waiting for what we want */
4015 return TRUE;
4019 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4020 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4022 UINT i;
4023 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4024 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4025 LPCSTR guidDataSubKey = "Guid";
4026 LPCSTR majVerDataSubKey = "dwReserved1";
4027 LPCSTR minVerDataSubKey = "dwReserved2";
4028 LPCSTR pathSubKey = "Path";
4030 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4032 /* FIXME: Cloned code with a quick hack. */
4033 for( i=0; i<2; i++ )
4035 HKEY hkResult;
4036 LPCSTR searchSubKey;
4037 char subKeyName[51];
4038 DWORD dwIndex, sizeOfSubKeyName=50;
4039 FILETIME filetime;
4041 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4042 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4045 /* Need to loop over the service providers in the registry */
4046 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4047 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4049 /* Hmmm. Does this mean that there are no service providers? */
4050 ERR(": no service providers?\n");
4051 return 0;
4054 /* Traverse all the service providers we have available */
4055 for( dwIndex=0;
4056 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4057 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4058 ++dwIndex, sizeOfSubKeyName=51 )
4061 HKEY hkServiceProvider;
4062 GUID serviceProviderGUID;
4063 DWORD returnType, sizeOfReturnBuffer = 255;
4064 char returnBuffer[256];
4065 WCHAR buff[51];
4066 DWORD dwTemp, len;
4068 TRACE(" this time through: %s\n", subKeyName );
4070 /* Get a handle for this particular service provider */
4071 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4072 &hkServiceProvider ) != ERROR_SUCCESS )
4074 ERR(": what the heck is going on?\n" );
4075 continue;
4078 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4079 NULL, &returnType, (LPBYTE)returnBuffer,
4080 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4082 ERR(": missing GUID registry data members\n" );
4083 continue;
4086 /* FIXME: Check return types to ensure we're interpreting data right */
4087 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4088 CLSIDFromString( buff, &serviceProviderGUID );
4089 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4091 /* Determine if this is the Service Provider that the user asked for */
4092 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4094 continue;
4097 if( i == 0 ) /* DP SP */
4099 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4100 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4101 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4104 sizeOfReturnBuffer = 255;
4106 /* Get dwReserved1 */
4107 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4108 NULL, &returnType, (LPBYTE)returnBuffer,
4109 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4111 ERR(": missing dwReserved1 registry data members\n") ;
4112 continue;
4115 if( i == 0 )
4116 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4118 sizeOfReturnBuffer = 255;
4120 /* Get dwReserved2 */
4121 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4122 NULL, &returnType, (LPBYTE)returnBuffer,
4123 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4125 ERR(": missing dwReserved1 registry data members\n") ;
4126 continue;
4129 if( i == 0 )
4130 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4132 sizeOfReturnBuffer = 255;
4134 /* Get the path for this service provider */
4135 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4136 NULL, NULL, (LPBYTE)returnBuffer,
4137 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4139 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4140 continue;
4143 TRACE( "Loading %s\n", returnBuffer );
4144 return LoadLibraryA( returnBuffer );
4148 return 0;
4151 static
4152 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4154 HRESULT hr;
4155 LPDPSP_SPINIT SPInit;
4157 /* Initialize the service provider by calling SPInit */
4158 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4160 if( SPInit == NULL )
4162 ERR( "Service provider doesn't provide SPInit interface?\n" );
4163 FreeLibrary( hServiceProvider );
4164 return DPERR_UNAVAILABLE;
4167 TRACE( "Calling SPInit (DP SP entry point)\n" );
4169 hr = (*SPInit)( &This->dp2->spData );
4171 if( FAILED(hr) )
4173 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4174 FreeLibrary( hServiceProvider );
4175 return hr;
4178 /* FIXME: Need to verify the sanity of the returned callback table
4179 * using IsBadCodePtr */
4180 This->dp2->bSPInitialized = TRUE;
4182 /* This interface is now initialized as a DP object */
4183 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4185 /* Store the handle of the module so that we can unload it later */
4186 This->dp2->hServiceProvider = hServiceProvider;
4188 return hr;
4191 static
4192 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4194 HRESULT hr;
4195 LPSP_INIT DPLSPInit;
4197 /* Initialize the service provider by calling SPInit */
4198 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4200 if( DPLSPInit == NULL )
4202 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4203 FreeLibrary( hLobbyProvider );
4204 return DPERR_UNAVAILABLE;
4207 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4209 hr = (*DPLSPInit)( &This->dp2->dplspData );
4211 if( FAILED(hr) )
4213 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4214 FreeLibrary( hLobbyProvider );
4215 return hr;
4218 /* FIXME: Need to verify the sanity of the returned callback table
4219 * using IsBadCodePtr */
4221 This->dp2->bDPLSPInitialized = TRUE;
4223 /* This interface is now initialized as a lobby object */
4224 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4226 /* Store the handle of the module so that we can unload it later */
4227 This->dp2->hDPLobbyProvider = hLobbyProvider;
4229 return hr;
4232 static HRESULT DP_IF_InitializeConnection
4233 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4235 HMODULE hServiceProvider;
4236 HRESULT hr;
4237 GUID guidSP;
4238 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4239 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4241 TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4243 if ( lpConnection == NULL )
4245 return DPERR_INVALIDPARAMS;
4248 if( dwFlags != 0 )
4250 return DPERR_INVALIDFLAGS;
4253 if( This->dp2->connectionInitialized != NO_PROVIDER )
4255 return DPERR_ALREADYINITIALIZED;
4258 /* Find out what the requested SP is and how large this buffer is */
4259 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4260 dwAddrSize, &guidSP );
4262 if( FAILED(hr) )
4264 ERR( "Invalid compound address?\n" );
4265 return DPERR_UNAVAILABLE;
4268 /* Load the service provider */
4269 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4271 if( hServiceProvider == 0 )
4273 ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4274 return DPERR_UNAVAILABLE;
4277 if( bIsDpSp )
4279 /* Fill in what we can of the Service Provider required information.
4280 * The rest was be done in DP_LoadSP
4282 This->dp2->spData.lpAddress = lpConnection;
4283 This->dp2->spData.dwAddressSize = dwAddrSize;
4284 This->dp2->spData.lpGuid = &guidSP;
4286 hr = DP_InitializeDPSP( This, hServiceProvider );
4288 else
4290 This->dp2->dplspData.lpAddress = lpConnection;
4292 hr = DP_InitializeDPLSP( This, hServiceProvider );
4295 if( FAILED(hr) )
4297 return hr;
4300 return DP_OK;
4303 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4304 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4306 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4308 /* This may not be externally invoked once either an SP or LP is initialized */
4309 if( This->dp2->connectionInitialized != NO_PROVIDER )
4311 return DPERR_ALREADYINITIALIZED;
4314 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4317 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4318 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4320 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4322 /* This may not be externally invoked once either an SP or LP is initialized */
4323 if( This->dp2->connectionInitialized != NO_PROVIDER )
4325 return DPERR_ALREADYINITIALIZED;
4328 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4331 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4332 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4333 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4335 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4336 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4339 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4340 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4341 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4343 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4344 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4347 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4348 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4350 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4351 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4352 return DP_OK;
4355 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4356 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4358 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4359 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4360 return DP_OK;
4363 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4364 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4366 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4367 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4368 return DP_OK;
4371 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4372 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4374 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4375 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4376 return DP_OK;
4379 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4380 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4382 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4383 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4384 return DP_OK;
4387 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4388 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4390 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4391 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4392 return DP_OK;
4395 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4396 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4398 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4399 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4400 return DP_OK;
4403 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4404 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4406 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4407 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4408 return DP_OK;
4411 static HRESULT DP_IF_GetGroupParent
4412 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4413 BOOL bAnsi )
4415 lpGroupData lpGData;
4417 TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4419 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4421 return DPERR_INVALIDGROUP;
4424 *lpidGroup = lpGData->dpid;
4426 return DP_OK;
4429 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4430 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4432 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4433 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4435 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4436 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4438 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4439 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4442 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4443 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4445 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4446 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4447 return DP_OK;
4450 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4451 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4453 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4454 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4455 return DP_OK;
4458 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4459 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4461 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4462 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4463 return DP_OK;
4466 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4467 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4469 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4470 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4471 return DP_OK;
4474 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4475 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4477 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4478 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4479 return DP_OK;
4482 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4483 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4485 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4486 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4487 return DP_OK;
4490 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4491 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4493 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4494 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4495 return DP_OK;
4498 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4499 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4501 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4502 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4503 return DP_OK;
4506 static HRESULT DP_SendEx
4507 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4508 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4509 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4511 BOOL bValidDestination = FALSE;
4513 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4514 ": stub\n",
4515 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4516 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4518 if( This->dp2->connectionInitialized == NO_PROVIDER )
4520 return DPERR_UNINITIALIZED;
4523 /* FIXME: Add parameter checking */
4524 /* FIXME: First call to this needs to acquire a message id which will be
4525 * used for multiple sends
4528 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4530 /* Verify that the message is being sent from a valid local player. The
4531 * from player may be anonymous DPID_UNKNOWN
4533 if( idFrom != DPID_UNKNOWN )
4535 if( DP_FindPlayer( This, idFrom ) == NULL )
4537 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4538 return DPERR_INVALIDPLAYER;
4542 /* Verify that the message is being sent to a valid player, group or to
4543 * everyone. If it's valid, send it to those players.
4545 if( idTo == DPID_ALLPLAYERS )
4547 bValidDestination = TRUE;
4549 /* See if SP has the ability to multicast. If so, use it */
4550 if( This->dp2->spData.lpCB->SendToGroupEx )
4552 FIXME( "Use group sendex to group 0\n" );
4554 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4556 FIXME( "Use obsolete group send to group 0\n" );
4558 else /* No multicast, multiplicate */
4560 /* Send to all players we know about */
4561 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4565 if( ( !bValidDestination ) &&
4566 ( DP_FindPlayer( This, idTo ) != NULL )
4569 /* Have the service provider send this message */
4570 /* FIXME: Could optimize for local interface sends */
4571 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4572 dwTimeout, lpContext, lpdwMsgID );
4575 if( ( !bValidDestination ) &&
4576 ( DP_FindAnyGroup( This, idTo ) != NULL )
4579 bValidDestination = TRUE;
4581 /* See if SP has the ability to multicast. If so, use it */
4582 if( This->dp2->spData.lpCB->SendToGroupEx )
4584 FIXME( "Use group sendex\n" );
4586 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4588 FIXME( "Use obsolete group send to group\n" );
4590 else /* No multicast, multiplicate */
4592 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4595 #if 0
4596 if( bExpectReply )
4598 DWORD dwWaitReturn;
4600 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4602 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4603 if( dwWaitReturn != WAIT_OBJECT_0 )
4605 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4608 #endif
4611 if( !bValidDestination )
4613 return DPERR_INVALIDPLAYER;
4615 else
4617 /* FIXME: Should return what the send returned */
4618 return DP_OK;
4623 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4624 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4625 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4626 LPVOID lpContext, LPDWORD lpdwMsgID )
4628 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4629 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4630 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4633 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4634 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4635 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4636 LPVOID lpContext, LPDWORD lpdwMsgID )
4638 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4639 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4640 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4643 static HRESULT DP_SP_SendEx
4644 ( IDirectPlay2Impl* This, DWORD dwFlags,
4645 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4646 LPVOID lpContext, LPDWORD lpdwMsgID )
4648 LPDPMSG lpMElem;
4650 FIXME( ": stub\n" );
4652 /* FIXME: This queuing should only be for async messages */
4654 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4655 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4657 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4659 /* FIXME: Need to queue based on priority */
4660 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4662 return DP_OK;
4665 static HRESULT DP_IF_GetMessageQueue
4666 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4667 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4669 HRESULT hr = DP_OK;
4671 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4672 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4674 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4675 /* FIXME: What about sends which are not immediate? */
4677 if( This->dp2->spData.lpCB->GetMessageQueue )
4679 DPSP_GETMESSAGEQUEUEDATA data;
4681 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4683 /* FIXME: None of this is documented :( */
4685 data.lpISP = This->dp2->spData.lpISP;
4686 data.dwFlags = dwFlags;
4687 data.idFrom = idFrom;
4688 data.idTo = idTo;
4689 data.lpdwNumMsgs = lpdwNumMsgs;
4690 data.lpdwNumBytes = lpdwNumBytes;
4692 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4694 else
4696 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4699 return hr;
4702 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4703 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4704 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4706 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4707 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4708 lpdwNumBytes, TRUE );
4711 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4712 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4713 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4715 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4716 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4717 lpdwNumBytes, FALSE );
4720 static HRESULT DP_IF_CancelMessage
4721 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4722 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4724 HRESULT hr = DP_OK;
4726 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4727 This, dwMsgID, dwFlags, bAnsi );
4729 if( This->dp2->spData.lpCB->Cancel )
4731 DPSP_CANCELDATA data;
4733 TRACE( "Calling SP Cancel\n" );
4735 /* FIXME: Undocumented callback */
4737 data.lpISP = This->dp2->spData.lpISP;
4738 data.dwFlags = dwFlags;
4739 data.lprglpvSPMsgID = NULL;
4740 data.cSPMsgID = dwMsgID;
4741 data.dwMinPriority = dwMinPriority;
4742 data.dwMaxPriority = dwMaxPriority;
4744 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4746 else
4748 FIXME( "SP doesn't implement Cancel\n" );
4751 return hr;
4754 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4755 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4757 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4759 if( dwFlags != 0 )
4761 return DPERR_INVALIDFLAGS;
4764 if( dwMsgID == 0 )
4766 dwFlags |= DPCANCELSEND_ALL;
4769 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4772 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4773 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4775 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4777 if( dwFlags != 0 )
4779 return DPERR_INVALIDFLAGS;
4782 if( dwMsgID == 0 )
4784 dwFlags |= DPCANCELSEND_ALL;
4787 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4790 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4791 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4792 DWORD dwFlags )
4794 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4796 if( dwFlags != 0 )
4798 return DPERR_INVALIDFLAGS;
4801 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4802 dwMaxPriority, TRUE );
4805 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4806 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4807 DWORD dwFlags )
4809 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4811 if( dwFlags != 0 )
4813 return DPERR_INVALIDFLAGS;
4816 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4817 dwMaxPriority, FALSE );
4820 /* Note: Hack so we can reuse the old functions without compiler warnings */
4821 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4822 # define XCAST(fun) (typeof(directPlay2WVT.fun))
4823 #else
4824 # define XCAST(fun) (void*)
4825 #endif
4827 static const IDirectPlay2Vtbl directPlay2WVT =
4829 XCAST(QueryInterface)DP_QueryInterface,
4830 XCAST(AddRef)DP_AddRef,
4831 XCAST(Release)DP_Release,
4833 DirectPlay2WImpl_AddPlayerToGroup,
4834 DirectPlay2WImpl_Close,
4835 DirectPlay2WImpl_CreateGroup,
4836 DirectPlay2WImpl_CreatePlayer,
4837 DirectPlay2WImpl_DeletePlayerFromGroup,
4838 DirectPlay2WImpl_DestroyGroup,
4839 DirectPlay2WImpl_DestroyPlayer,
4840 DirectPlay2WImpl_EnumGroupPlayers,
4841 DirectPlay2WImpl_EnumGroups,
4842 DirectPlay2WImpl_EnumPlayers,
4843 DirectPlay2WImpl_EnumSessions,
4844 DirectPlay2WImpl_GetCaps,
4845 DirectPlay2WImpl_GetGroupData,
4846 DirectPlay2WImpl_GetGroupName,
4847 DirectPlay2WImpl_GetMessageCount,
4848 DirectPlay2WImpl_GetPlayerAddress,
4849 DirectPlay2WImpl_GetPlayerCaps,
4850 DirectPlay2WImpl_GetPlayerData,
4851 DirectPlay2WImpl_GetPlayerName,
4852 DirectPlay2WImpl_GetSessionDesc,
4853 DirectPlay2WImpl_Initialize,
4854 DirectPlay2WImpl_Open,
4855 DirectPlay2WImpl_Receive,
4856 DirectPlay2WImpl_Send,
4857 DirectPlay2WImpl_SetGroupData,
4858 DirectPlay2WImpl_SetGroupName,
4859 DirectPlay2WImpl_SetPlayerData,
4860 DirectPlay2WImpl_SetPlayerName,
4861 DirectPlay2WImpl_SetSessionDesc
4863 #undef XCAST
4865 /* Note: Hack so we can reuse the old functions without compiler warnings */
4866 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4867 # define XCAST(fun) (typeof(directPlay2AVT.fun))
4868 #else
4869 # define XCAST(fun) (void*)
4870 #endif
4872 static const IDirectPlay2Vtbl directPlay2AVT =
4874 XCAST(QueryInterface)DP_QueryInterface,
4875 XCAST(AddRef)DP_AddRef,
4876 XCAST(Release)DP_Release,
4878 DirectPlay2AImpl_AddPlayerToGroup,
4879 DirectPlay2AImpl_Close,
4880 DirectPlay2AImpl_CreateGroup,
4881 DirectPlay2AImpl_CreatePlayer,
4882 DirectPlay2AImpl_DeletePlayerFromGroup,
4883 DirectPlay2AImpl_DestroyGroup,
4884 DirectPlay2AImpl_DestroyPlayer,
4885 DirectPlay2AImpl_EnumGroupPlayers,
4886 DirectPlay2AImpl_EnumGroups,
4887 DirectPlay2AImpl_EnumPlayers,
4888 DirectPlay2AImpl_EnumSessions,
4889 DirectPlay2AImpl_GetCaps,
4890 DirectPlay2AImpl_GetGroupData,
4891 DirectPlay2AImpl_GetGroupName,
4892 DirectPlay2AImpl_GetMessageCount,
4893 DirectPlay2AImpl_GetPlayerAddress,
4894 DirectPlay2AImpl_GetPlayerCaps,
4895 DirectPlay2AImpl_GetPlayerData,
4896 DirectPlay2AImpl_GetPlayerName,
4897 DirectPlay2AImpl_GetSessionDesc,
4898 DirectPlay2AImpl_Initialize,
4899 DirectPlay2AImpl_Open,
4900 DirectPlay2AImpl_Receive,
4901 DirectPlay2AImpl_Send,
4902 DirectPlay2AImpl_SetGroupData,
4903 DirectPlay2AImpl_SetGroupName,
4904 DirectPlay2AImpl_SetPlayerData,
4905 DirectPlay2AImpl_SetPlayerName,
4906 DirectPlay2AImpl_SetSessionDesc
4908 #undef XCAST
4911 /* Note: Hack so we can reuse the old functions without compiler warnings */
4912 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4913 # define XCAST(fun) (typeof(directPlay3AVT.fun))
4914 #else
4915 # define XCAST(fun) (void*)
4916 #endif
4918 static const IDirectPlay3Vtbl directPlay3AVT =
4920 XCAST(QueryInterface)DP_QueryInterface,
4921 XCAST(AddRef)DP_AddRef,
4922 XCAST(Release)DP_Release,
4924 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
4925 XCAST(Close)DirectPlay2AImpl_Close,
4926 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
4927 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
4928 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
4929 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
4930 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
4931 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
4932 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
4933 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
4934 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
4935 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
4936 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
4937 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
4938 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
4939 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
4940 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
4941 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
4942 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
4943 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
4944 XCAST(Initialize)DirectPlay2AImpl_Initialize,
4945 XCAST(Open)DirectPlay2AImpl_Open,
4946 XCAST(Receive)DirectPlay2AImpl_Receive,
4947 XCAST(Send)DirectPlay2AImpl_Send,
4948 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
4949 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
4950 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
4951 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
4952 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
4954 DirectPlay3AImpl_AddGroupToGroup,
4955 DirectPlay3AImpl_CreateGroupInGroup,
4956 DirectPlay3AImpl_DeleteGroupFromGroup,
4957 DirectPlay3AImpl_EnumConnections,
4958 DirectPlay3AImpl_EnumGroupsInGroup,
4959 DirectPlay3AImpl_GetGroupConnectionSettings,
4960 DirectPlay3AImpl_InitializeConnection,
4961 DirectPlay3AImpl_SecureOpen,
4962 DirectPlay3AImpl_SendChatMessage,
4963 DirectPlay3AImpl_SetGroupConnectionSettings,
4964 DirectPlay3AImpl_StartSession,
4965 DirectPlay3AImpl_GetGroupFlags,
4966 DirectPlay3AImpl_GetGroupParent,
4967 DirectPlay3AImpl_GetPlayerAccount,
4968 DirectPlay3AImpl_GetPlayerFlags
4970 #undef XCAST
4972 /* Note: Hack so we can reuse the old functions without compiler warnings */
4973 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4974 # define XCAST(fun) (typeof(directPlay3WVT.fun))
4975 #else
4976 # define XCAST(fun) (void*)
4977 #endif
4978 static const IDirectPlay3Vtbl directPlay3WVT =
4980 XCAST(QueryInterface)DP_QueryInterface,
4981 XCAST(AddRef)DP_AddRef,
4982 XCAST(Release)DP_Release,
4984 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
4985 XCAST(Close)DirectPlay2WImpl_Close,
4986 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
4987 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
4988 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
4989 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
4990 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
4991 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
4992 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
4993 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
4994 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
4995 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
4996 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
4997 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
4998 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
4999 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5000 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5001 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5002 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5003 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5004 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5005 XCAST(Open)DirectPlay2WImpl_Open,
5006 XCAST(Receive)DirectPlay2WImpl_Receive,
5007 XCAST(Send)DirectPlay2WImpl_Send,
5008 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5009 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5010 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5011 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5012 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5014 DirectPlay3WImpl_AddGroupToGroup,
5015 DirectPlay3WImpl_CreateGroupInGroup,
5016 DirectPlay3WImpl_DeleteGroupFromGroup,
5017 DirectPlay3WImpl_EnumConnections,
5018 DirectPlay3WImpl_EnumGroupsInGroup,
5019 DirectPlay3WImpl_GetGroupConnectionSettings,
5020 DirectPlay3WImpl_InitializeConnection,
5021 DirectPlay3WImpl_SecureOpen,
5022 DirectPlay3WImpl_SendChatMessage,
5023 DirectPlay3WImpl_SetGroupConnectionSettings,
5024 DirectPlay3WImpl_StartSession,
5025 DirectPlay3WImpl_GetGroupFlags,
5026 DirectPlay3WImpl_GetGroupParent,
5027 DirectPlay3WImpl_GetPlayerAccount,
5028 DirectPlay3WImpl_GetPlayerFlags
5030 #undef XCAST
5032 /* Note: Hack so we can reuse the old functions without compiler warnings */
5033 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5034 # define XCAST(fun) (typeof(directPlay4WVT.fun))
5035 #else
5036 # define XCAST(fun) (void*)
5037 #endif
5038 static const IDirectPlay4Vtbl directPlay4WVT =
5040 XCAST(QueryInterface)DP_QueryInterface,
5041 XCAST(AddRef)DP_AddRef,
5042 XCAST(Release)DP_Release,
5044 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5045 XCAST(Close)DirectPlay2WImpl_Close,
5046 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5047 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5048 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5049 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5050 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5051 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5052 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5053 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5054 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5055 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5056 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5057 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5058 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5059 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5060 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5061 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5062 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5063 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5064 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5065 XCAST(Open)DirectPlay2WImpl_Open,
5066 XCAST(Receive)DirectPlay2WImpl_Receive,
5067 XCAST(Send)DirectPlay2WImpl_Send,
5068 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5069 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5070 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5071 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5072 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5074 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5075 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5076 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5077 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5078 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5079 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5080 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5081 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5082 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5083 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5084 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5085 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5086 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5087 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5088 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5090 DirectPlay4WImpl_GetGroupOwner,
5091 DirectPlay4WImpl_SetGroupOwner,
5092 DirectPlay4WImpl_SendEx,
5093 DirectPlay4WImpl_GetMessageQueue,
5094 DirectPlay4WImpl_CancelMessage,
5095 DirectPlay4WImpl_CancelPriority
5097 #undef XCAST
5100 /* Note: Hack so we can reuse the old functions without compiler warnings */
5101 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5102 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5103 #else
5104 # define XCAST(fun) (void*)
5105 #endif
5106 static const IDirectPlay4Vtbl directPlay4AVT =
5108 XCAST(QueryInterface)DP_QueryInterface,
5109 XCAST(AddRef)DP_AddRef,
5110 XCAST(Release)DP_Release,
5112 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5113 XCAST(Close)DirectPlay2AImpl_Close,
5114 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5115 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5116 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5117 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5118 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5119 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5120 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5121 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5122 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5123 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5124 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5125 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5126 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5127 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5128 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5129 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5130 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5131 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5132 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5133 XCAST(Open)DirectPlay2AImpl_Open,
5134 XCAST(Receive)DirectPlay2AImpl_Receive,
5135 XCAST(Send)DirectPlay2AImpl_Send,
5136 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5137 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5138 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5139 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5140 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5142 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5143 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5144 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5145 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5146 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5147 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5148 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5149 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5150 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5151 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5152 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5153 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5154 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5155 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5156 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5158 DirectPlay4AImpl_GetGroupOwner,
5159 DirectPlay4AImpl_SetGroupOwner,
5160 DirectPlay4AImpl_SendEx,
5161 DirectPlay4AImpl_GetMessageQueue,
5162 DirectPlay4AImpl_CancelMessage,
5163 DirectPlay4AImpl_CancelPriority
5165 #undef XCAST
5167 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5168 DPID idPlayer,
5169 LPVOID* lplpData )
5171 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5173 if( lpPlayer == NULL )
5175 return DPERR_INVALIDPLAYER;
5178 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5180 return DP_OK;
5183 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5184 DPID idPlayer,
5185 LPVOID lpData )
5187 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5189 if( lpPlayer == NULL )
5191 return DPERR_INVALIDPLAYER;
5194 lpPlayer->lpPData->lpSPPlayerData = lpData;
5196 return DP_OK;
5199 /***************************************************************************
5200 * DirectPlayEnumerateAW
5202 * The pointer to the structure lpContext will be filled with the
5203 * appropriate data for each service offered by the OS. These services are
5204 * not necessarily available on this particular machine but are defined
5205 * as simple service providers under the "Service Providers" registry key.
5206 * This structure is then passed to lpEnumCallback for each of the different
5207 * services.
5209 * This API is useful only for applications written using DirectX3 or
5210 * worse. It is superseded by IDirectPlay3::EnumConnections which also
5211 * gives information on the actual connections.
5213 * defn of a service provider:
5214 * A dynamic-link library used by DirectPlay to communicate over a network.
5215 * The service provider contains all the network-specific code required
5216 * to send and receive messages. Online services and network operators can
5217 * supply service providers to use specialized hardware, protocols, communications
5218 * media, and network resources.
5221 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5222 LPDPENUMDPCALLBACKW lpEnumCallbackW,
5223 LPVOID lpContext)
5225 HKEY hkResult;
5226 static const WCHAR searchSubKey[] = {
5227 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5228 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5229 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5230 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5231 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5232 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5234 DWORD dwIndex;
5235 FILETIME filetime;
5237 char *descriptionA = NULL;
5238 DWORD max_sizeOfDescriptionA = 0;
5239 WCHAR *descriptionW = NULL;
5240 DWORD max_sizeOfDescriptionW = 0;
5242 if (!lpEnumCallbackA && !lpEnumCallbackW)
5244 return DPERR_INVALIDPARAMS;
5247 /* Need to loop over the service providers in the registry */
5248 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5249 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5251 /* Hmmm. Does this mean that there are no service providers? */
5252 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5253 return DPERR_GENERIC;
5256 /* Traverse all the service providers we have available */
5257 dwIndex = 0;
5258 while (1)
5260 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5261 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5262 HKEY hkServiceProvider;
5263 GUID serviceProviderGUID;
5264 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5265 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5266 LONG ret_value;
5268 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5269 NULL, NULL, NULL, &filetime);
5270 if (ret_value == ERROR_NO_MORE_ITEMS)
5271 break;
5272 else if (ret_value != ERROR_SUCCESS)
5274 ERR(": could not enumerate on service provider key.\n");
5275 return DPERR_EXCEPTION;
5277 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5279 /* Open the key for this service provider */
5280 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5282 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5283 continue;
5286 /* Get the GUID from the registry */
5287 if (RegQueryValueExW(hkServiceProvider, guidKey,
5288 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5290 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5291 continue;
5293 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5295 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5296 continue;
5298 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5300 /* The enumeration will return FALSE if we are not to continue.
5302 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5303 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5304 * I think that it simply means that they are in-line with DirectX 6.0
5306 if (lpEnumCallbackA)
5308 DWORD sizeOfDescription = 0;
5310 /* Note that this is the A case of this function, so use the A variant to get the description string */
5311 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5312 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5314 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5315 continue;
5317 if (sizeOfDescription > max_sizeOfDescriptionA)
5319 HeapFree(GetProcessHeap(), 0, descriptionA);
5320 max_sizeOfDescriptionA = sizeOfDescription;
5322 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5323 RegQueryValueExA(hkServiceProvider, "DescriptionA",
5324 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5326 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5327 goto end;
5329 else
5331 DWORD sizeOfDescription = 0;
5333 if (RegQueryValueExW(hkServiceProvider, descW,
5334 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5336 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5337 continue;
5339 if (sizeOfDescription > max_sizeOfDescriptionW)
5341 HeapFree(GetProcessHeap(), 0, descriptionW);
5342 max_sizeOfDescriptionW = sizeOfDescription;
5344 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5345 RegQueryValueExW(hkServiceProvider, descW,
5346 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5348 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5349 goto end;
5352 dwIndex++;
5355 end:
5356 HeapFree(GetProcessHeap(), 0, descriptionA);
5357 HeapFree(GetProcessHeap(), 0, descriptionW);
5359 return DP_OK;
5362 /***************************************************************************
5363 * DirectPlayEnumerate [DPLAYX.9]
5364 * DirectPlayEnumerateA [DPLAYX.2]
5366 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5368 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5370 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5373 /***************************************************************************
5374 * DirectPlayEnumerateW [DPLAYX.3]
5376 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5378 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5380 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5383 typedef struct tagCreateEnum
5385 LPVOID lpConn;
5386 LPCGUID lpGuid;
5387 } CreateEnumData, *lpCreateEnumData;
5389 /* Find and copy the matching connection for the SP guid */
5390 static BOOL CALLBACK cbDPCreateEnumConnections(
5391 LPCGUID lpguidSP,
5392 LPVOID lpConnection,
5393 DWORD dwConnectionSize,
5394 LPCDPNAME lpName,
5395 DWORD dwFlags,
5396 LPVOID lpContext)
5398 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5400 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5402 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5404 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5405 dwConnectionSize );
5406 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5408 /* Found the record that we were looking for */
5409 return FALSE;
5412 /* Haven't found what were looking for yet */
5413 return TRUE;
5417 /***************************************************************************
5418 * DirectPlayCreate [DPLAYX.1]
5421 HRESULT WINAPI DirectPlayCreate
5422 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5424 HRESULT hr;
5425 LPDIRECTPLAY3A lpDP3A;
5426 CreateEnumData cbData;
5428 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5430 if( pUnk != NULL )
5432 return CLASS_E_NOAGGREGATION;
5435 if( (lplpDP == NULL) || (lpGUID == NULL) )
5437 return DPERR_INVALIDPARAMS;
5441 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5442 give them an IDirectPlay2A object and hope that doesn't cause problems */
5443 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5445 return DPERR_UNAVAILABLE;
5448 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5450 /* The GUID_NULL means don't bind a service provider. Just return the
5451 interface as is */
5452 return DP_OK;
5455 /* Bind the desired service provider since lpGUID is non NULL */
5456 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5458 /* We're going to use a DP3 interface */
5459 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5460 (LPVOID*)&lpDP3A );
5461 if( FAILED(hr) )
5463 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5464 return hr;
5467 cbData.lpConn = NULL;
5468 cbData.lpGuid = lpGUID;
5470 /* We were given a service provider, find info about it... */
5471 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5472 &cbData, DPCONNECTION_DIRECTPLAY );
5473 if( ( FAILED(hr) ) ||
5474 ( cbData.lpConn == NULL )
5477 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5478 IDirectPlayX_Release( lpDP3A );
5479 return DPERR_UNAVAILABLE;
5482 /* Initialize the service provider */
5483 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5484 if( FAILED(hr) )
5486 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5487 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5488 IDirectPlayX_Release( lpDP3A );
5489 return hr;
5492 /* Release our version of the interface now that we're done with it */
5493 IDirectPlayX_Release( lpDP3A );
5494 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5496 return DP_OK;