push 3600ceb9798742c4473b49518e0ae238427fc4b7
[wine/hacks.git] / dlls / dplayx / dplay.c
blob360e22b084064b58ce87c41f3af678a1036cd3e9
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 = (IDirectPlay2AImpl *)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 = (IDirectPlay2AImpl *)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 = (IDirectPlay2AImpl *)lpDP;
266 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
267 if ( This->dp2 == NULL )
269 return FALSE;
272 This->dp2->bConnectionOpen = FALSE;
274 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
275 This->dp2->dwEnumSessionLock = 0;
277 This->dp2->bHostInterface = FALSE;
279 DPQ_INIT(This->dp2->receiveMsgs);
280 DPQ_INIT(This->dp2->sendMsgs);
281 DPQ_INIT(This->dp2->replysExpected);
283 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
285 /* FIXME: Memory leak */
286 return FALSE;
289 /* Provide an initial session desc with nothing in it */
290 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
291 HEAP_ZERO_MEMORY,
292 sizeof( *This->dp2->lpSessionDesc ) );
293 if( This->dp2->lpSessionDesc == NULL )
295 /* FIXME: Memory leak */
296 return FALSE;
298 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
300 /* We are emulating a dp 6 implementation */
301 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
303 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
304 sizeof( *This->dp2->spData.lpCB ) );
305 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
306 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
308 /* This is the pointer to the service provider */
309 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
310 (LPVOID*)&This->dp2->spData.lpISP, This ) )
313 /* FIXME: Memory leak */
314 return FALSE;
317 /* Setup lobby provider information */
318 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
319 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
320 sizeof( *This->dp2->dplspData.lpCB ) );
321 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
323 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
324 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
327 /* FIXME: Memory leak */
328 return FALSE;
331 return TRUE;
334 /* Definition of the global function in dplayx_queue.h. #
335 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
336 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
338 HeapFree( GetProcessHeap(), 0, elem );
341 /* Function to delete the list of groups with this interface. Needs to
342 * delete the group and player lists associated with this group as well
343 * as the group data associated with this group. It should not delete
344 * player data as that is shared with the top player list and will be
345 * deleted with that.
347 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList );
348 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList )
350 DPQ_DELETEQ( elem->lpGData->groups, groups,
351 lpGroupList, cbDeleteElemFromHeap );
352 DPQ_DELETEQ( elem->lpGData->players, players,
353 lpPlayerList, cbDeleteElemFromHeap );
354 HeapFree( GetProcessHeap(), 0, elem->lpGData );
355 HeapFree( GetProcessHeap(), 0, elem );
358 /* Function to delete the list of players with this interface. Needs to
359 * delete the player data for all players as well.
361 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList );
362 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList )
364 HeapFree( GetProcessHeap(), 0, elem->lpPData );
365 HeapFree( GetProcessHeap(), 0, elem );
368 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
370 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
372 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
374 TerminateThread( This->dp2->hEnumSessionThread, 0 );
375 CloseHandle( This->dp2->hEnumSessionThread );
378 /* Finish with the SP - have it shutdown */
379 if( This->dp2->spData.lpCB->ShutdownEx )
381 DPSP_SHUTDOWNDATA data;
383 TRACE( "Calling SP ShutdownEx\n" );
385 data.lpISP = This->dp2->spData.lpISP;
387 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
389 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
391 TRACE( "Calling obsolete SP Shutdown\n" );
392 (*This->dp2->spData.lpCB->Shutdown)();
395 /* Unload the SP (if it exists) */
396 if( This->dp2->hServiceProvider != 0 )
398 FreeLibrary( This->dp2->hServiceProvider );
401 /* Unload the Lobby Provider (if it exists) */
402 if( This->dp2->hDPLobbyProvider != 0 )
404 FreeLibrary( This->dp2->hDPLobbyProvider );
407 #if 0
408 DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
409 DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem );
410 #endif
412 /* FIXME: Need to delete receive and send msgs queue contents */
414 NS_DeleteSessionCache( This->dp2->lpNameServerData );
416 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
418 IDirectPlaySP_Release( This->dp2->spData.lpISP );
420 /* Delete the contents */
421 HeapFree( GetProcessHeap(), 0, This->dp2 );
423 return TRUE;
426 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
428 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
430 This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
431 if ( This->dp3 == NULL )
433 return FALSE;
436 return TRUE;
439 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
441 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
443 /* Delete the contents */
444 HeapFree( GetProcessHeap(), 0, This->dp3 );
446 return TRUE;
449 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
451 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)lpDP;
453 This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
454 if ( This->dp4 == NULL )
456 return FALSE;
459 return TRUE;
462 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
464 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
466 /* Delete the contents */
467 HeapFree( GetProcessHeap(), 0, This->dp4 );
469 return TRUE;
473 /* Create a new interface */
474 HRESULT DP_CreateInterface
475 ( REFIID riid, LPVOID* ppvObj )
477 TRACE( " for %s\n", debugstr_guid( riid ) );
479 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
480 sizeof( IDirectPlay2Impl ) );
482 if( *ppvObj == NULL )
484 return DPERR_OUTOFMEMORY;
487 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
489 IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
490 This->lpVtbl = &directPlay2WVT;
492 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
494 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
495 This->lpVtbl = &directPlay2AVT;
497 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
499 IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
500 This->lpVtbl = &directPlay3WVT;
502 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
504 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
505 This->lpVtbl = &directPlay3AVT;
507 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
509 IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
510 This->lpVtbl = &directPlay4WVT;
512 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
514 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
515 This->lpVtbl = &directPlay4AVT;
517 else
519 /* Unsupported interface */
520 HeapFree( GetProcessHeap(), 0, *ppvObj );
521 *ppvObj = NULL;
523 return E_NOINTERFACE;
526 /* Initialize it */
527 if ( DP_CreateIUnknown( *ppvObj ) &&
528 DP_CreateDirectPlay2( *ppvObj ) &&
529 DP_CreateDirectPlay3( *ppvObj ) &&
530 DP_CreateDirectPlay4( *ppvObj )
533 IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
535 return S_OK;
538 /* Initialize failed, destroy it */
539 DP_DestroyDirectPlay4( *ppvObj );
540 DP_DestroyDirectPlay3( *ppvObj );
541 DP_DestroyDirectPlay2( *ppvObj );
542 DP_DestroyIUnknown( *ppvObj );
544 HeapFree( GetProcessHeap(), 0, *ppvObj );
546 *ppvObj = NULL;
547 return DPERR_NOMEMORY;
551 /* Direct Play methods */
553 /* Shared between all dplay types */
554 static HRESULT WINAPI DP_QueryInterface
555 ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
557 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
558 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
560 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
561 sizeof( *This ) );
563 if( *ppvObj == NULL )
565 return DPERR_OUTOFMEMORY;
568 CopyMemory( *ppvObj, This, sizeof( *This ) );
569 (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
571 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
573 IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
574 This->lpVtbl = &directPlay2WVT;
576 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
578 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
579 This->lpVtbl = &directPlay2AVT;
581 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
583 IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
584 This->lpVtbl = &directPlay3WVT;
586 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
588 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
589 This->lpVtbl = &directPlay3AVT;
591 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
593 IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
594 This->lpVtbl = &directPlay4WVT;
596 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
598 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
599 This->lpVtbl = &directPlay4AVT;
601 else
603 /* Unsupported interface */
604 HeapFree( GetProcessHeap(), 0, *ppvObj );
605 *ppvObj = NULL;
607 return E_NOINTERFACE;
610 IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
612 return S_OK;
615 /* Shared between all dplay types */
616 static ULONG WINAPI DP_AddRef
617 ( LPDIRECTPLAY3 iface )
619 ULONG ulInterfaceRefCount, ulObjRefCount;
620 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
622 ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
623 ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
625 TRACE( "ref count incremented to %u:%u for %p\n",
626 ulInterfaceRefCount, ulObjRefCount, This );
628 return ulObjRefCount;
631 static ULONG WINAPI DP_Release
632 ( LPDIRECTPLAY3 iface )
634 ULONG ulInterfaceRefCount, ulObjRefCount;
636 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
638 ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
639 ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
641 TRACE( "ref count decremented to %u:%u for %p\n",
642 ulInterfaceRefCount, ulObjRefCount, This );
644 /* Deallocate if this is the last reference to the object */
645 if( ulObjRefCount == 0 )
647 /* If we're destroying the object, this must be the last ref
648 of the last interface */
649 DP_DestroyDirectPlay4( This );
650 DP_DestroyDirectPlay3( This );
651 DP_DestroyDirectPlay2( This );
652 DP_DestroyIUnknown( This );
655 /* Deallocate the interface */
656 if( ulInterfaceRefCount == 0 )
658 HeapFree( GetProcessHeap(), 0, This );
661 return ulObjRefCount;
664 static inline DPID DP_NextObjectId(void)
666 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
669 /* *lplpReply will be non NULL iff there is something to reply */
670 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
671 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
672 WORD wCommandId, WORD wVersion,
673 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
675 TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
676 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
677 wVersion );
679 switch( wCommandId )
681 /* Name server needs to handle this request */
682 case DPMSGCMD_ENUMSESSIONSREQUEST:
684 /* Reply expected */
685 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
687 break;
690 /* Name server needs to handle this request */
691 case DPMSGCMD_ENUMSESSIONSREPLY:
693 /* No reply expected */
694 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
695 This->dp2->spData.dwSPHeaderSize,
696 lpcMessageBody,
697 This->dp2->lpNameServerData );
698 break;
701 case DPMSGCMD_REQUESTNEWPLAYERID:
703 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg =
704 (LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody;
706 LPDPMSG_NEWPLAYERIDREPLY lpReply;
708 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
710 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
712 FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
713 lpcMsg->dwFlags );
715 /* Setup the reply */
716 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
717 This->dp2->spData.dwSPHeaderSize );
719 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
720 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
721 lpReply->envelope.wVersion = DPMSGVER_DP6;
723 lpReply->dpidNewPlayerId = DP_NextObjectId();
725 TRACE( "Allocating new playerid 0x%08x from remote request\n",
726 lpReply->dpidNewPlayerId );
728 break;
731 case DPMSGCMD_GETNAMETABLEREPLY:
732 case DPMSGCMD_NEWPLAYERIDREPLY:
735 #if 0
736 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
737 DebugBreak();
738 #endif
739 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
741 break;
744 #if 1
745 case DPMSGCMD_JUSTENVELOPE:
747 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
748 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
749 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
751 #endif
753 case DPMSGCMD_FORWARDADDPLAYER:
755 #if 0
756 DebugBreak();
757 #endif
758 #if 1
759 TRACE( "Sending message to self to get my addr\n" );
760 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
761 #endif
762 break;
765 case DPMSGCMD_FORWARDADDPLAYERNACK:
767 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
768 break;
771 default:
773 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
774 DebugBreak();
775 break;
779 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
781 return DP_OK;
785 static HRESULT DP_IF_AddPlayerToGroup
786 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
787 DPID idPlayer, BOOL bAnsi )
789 lpGroupData lpGData;
790 lpPlayerList lpPList;
791 lpPlayerList lpNewPList;
793 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
794 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
796 if( This->dp2->connectionInitialized == NO_PROVIDER )
798 return DPERR_UNINITIALIZED;
801 /* Find the group */
802 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
804 return DPERR_INVALIDGROUP;
807 /* Find the player */
808 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
810 return DPERR_INVALIDPLAYER;
813 /* Create a player list (ie "shortcut" ) */
814 lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
815 if( lpNewPList == NULL )
817 return DPERR_CANTADDPLAYER;
820 /* Add the shortcut */
821 lpPList->lpPData->uRef++;
822 lpNewPList->lpPData = lpPList->lpPData;
824 /* Add the player to the list of players for this group */
825 DPQ_INSERT(lpGData->players,lpNewPList,players);
827 /* Let the SP know that we've added a player to the group */
828 if( This->dp2->spData.lpCB->AddPlayerToGroup )
830 DPSP_ADDPLAYERTOGROUPDATA data;
832 TRACE( "Calling SP AddPlayerToGroup\n" );
834 data.idPlayer = idPlayer;
835 data.idGroup = idGroup;
836 data.lpISP = This->dp2->spData.lpISP;
838 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
841 /* Inform all other peers of the addition of player to the group. If there are
842 * no peers keep this event quiet.
843 * Also, if this event was the result of another machine sending it to us,
844 * don't bother rebroadcasting it.
846 if( ( lpMsgHdr == NULL ) &&
847 This->dp2->lpSessionDesc &&
848 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
850 DPMSG_ADDPLAYERTOGROUP msg;
851 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
853 msg.dpIdGroup = idGroup;
854 msg.dpIdPlayer = idPlayer;
856 /* FIXME: Correct to just use send effectively? */
857 /* FIXME: Should size include data w/ message or just message "header" */
858 /* FIXME: Check return code */
859 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
862 return DP_OK;
865 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
866 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
868 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
869 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
872 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
873 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
875 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
876 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
879 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
881 HRESULT hr = DP_OK;
883 TRACE("(%p)->(%u)\n", This, bAnsi );
885 /* FIXME: Need to find a new host I assume (how?) */
886 /* FIXME: Need to destroy all local groups */
887 /* FIXME: Need to migrate all remotely visible players to the new host */
889 /* Invoke the SP callback to inform of session close */
890 if( This->dp2->spData.lpCB->CloseEx )
892 DPSP_CLOSEDATA data;
894 TRACE( "Calling SP CloseEx\n" );
896 data.lpISP = This->dp2->spData.lpISP;
898 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
901 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
903 TRACE( "Calling SP Close (obsolete interface)\n" );
905 hr = (*This->dp2->spData.lpCB->Close)();
908 return hr;
911 static HRESULT WINAPI DirectPlay2AImpl_Close
912 ( LPDIRECTPLAY2A iface )
914 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
915 return DP_IF_Close( This, TRUE );
918 static HRESULT WINAPI DirectPlay2WImpl_Close
919 ( LPDIRECTPLAY2 iface )
921 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
922 return DP_IF_Close( This, FALSE );
925 static
926 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
927 const DPNAME *lpName, DWORD dwFlags,
928 DPID idParent, BOOL bAnsi )
930 lpGroupData lpGData;
932 /* Allocate the new space and add to end of high level group list */
933 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
935 if( lpGData == NULL )
937 return NULL;
940 DPQ_INIT(lpGData->groups);
941 DPQ_INIT(lpGData->players);
943 /* Set the desired player ID - no sanity checking to see if it exists */
944 lpGData->dpid = *lpid;
946 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
948 /* FIXME: Should we check that the parent exists? */
949 lpGData->parent = idParent;
951 /* FIXME: Should we validate the dwFlags? */
952 lpGData->dwFlags = dwFlags;
954 TRACE( "Created group id 0x%08x\n", *lpid );
956 return lpGData;
959 /* This method assumes that all links to it are already deleted */
960 static void
961 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
963 lpGroupList lpGList;
965 TRACE( "(%p)->(0x%08x)\n", This, dpid );
967 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
969 if( lpGList == NULL )
971 ERR( "DPID 0x%08x not found\n", dpid );
972 return;
975 if( --(lpGList->lpGData->uRef) )
977 FIXME( "Why is this not the last reference to group?\n" );
978 DebugBreak();
981 /* Delete player */
982 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
983 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
985 /* Remove and Delete Player List object */
986 HeapFree( GetProcessHeap(), 0, lpGList );
990 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
992 lpGroupList lpGroups;
994 TRACE( "(%p)->(0x%08x)\n", This, dpid );
996 if( dpid == DPID_SYSTEM_GROUP )
998 return This->dp2->lpSysGroup;
1000 else
1002 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
1005 if( lpGroups == NULL )
1007 return NULL;
1010 return lpGroups->lpGData;
1013 static HRESULT DP_IF_CreateGroup
1014 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
1015 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
1016 DWORD dwFlags, BOOL bAnsi )
1018 lpGroupData lpGData;
1020 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1021 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
1022 dwFlags, bAnsi );
1024 if( This->dp2->connectionInitialized == NO_PROVIDER )
1026 return DPERR_UNINITIALIZED;
1029 /* If the name is not specified, we must provide one */
1030 if( DPID_UNKNOWN == *lpidGroup )
1032 /* If we are the name server, we decide on the group ids. If not, we
1033 * must ask for one before attempting a creation.
1035 if( This->dp2->bHostInterface )
1037 *lpidGroup = DP_NextObjectId();
1039 else
1041 *lpidGroup = DP_GetRemoteNextObjectId();
1045 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1046 DPID_NOPARENT_GROUP, bAnsi );
1048 if( lpGData == NULL )
1050 return DPERR_CANTADDPLAYER; /* yes player not group */
1053 if( DPID_SYSTEM_GROUP == *lpidGroup )
1055 This->dp2->lpSysGroup = lpGData;
1056 TRACE( "Inserting system group\n" );
1058 else
1060 /* Insert into the system group */
1061 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1062 lpGroup->lpGData = lpGData;
1064 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1067 /* Something is now referencing this data */
1068 lpGData->uRef++;
1070 /* Set all the important stuff for the group */
1071 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1073 /* FIXME: We should only create the system group if GetCaps returns
1074 * DPCAPS_GROUPOPTIMIZED.
1077 /* Let the SP know that we've created this group */
1078 if( This->dp2->spData.lpCB->CreateGroup )
1080 DPSP_CREATEGROUPDATA data;
1081 DWORD dwCreateFlags = 0;
1083 TRACE( "Calling SP CreateGroup\n" );
1085 if( *lpidGroup == DPID_NOPARENT_GROUP )
1086 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1088 if( lpMsgHdr == NULL )
1089 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1091 if( dwFlags & DPGROUP_HIDDEN )
1092 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1094 data.idGroup = *lpidGroup;
1095 data.dwFlags = dwCreateFlags;
1096 data.lpSPMessageHeader = lpMsgHdr;
1097 data.lpISP = This->dp2->spData.lpISP;
1099 (*This->dp2->spData.lpCB->CreateGroup)( &data );
1102 /* Inform all other peers of the creation of a new group. If there are
1103 * no peers keep this event quiet.
1104 * Also if this message was sent to us, don't rebroadcast.
1106 if( ( lpMsgHdr == NULL ) &&
1107 This->dp2->lpSessionDesc &&
1108 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1110 DPMSG_CREATEPLAYERORGROUP msg;
1111 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1113 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
1114 msg.dpId = *lpidGroup;
1115 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1116 msg.lpData = lpData;
1117 msg.dwDataSize = dwDataSize;
1118 msg.dpnName = *lpGroupName;
1119 msg.dpIdParent = DPID_NOPARENT_GROUP;
1120 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1122 /* FIXME: Correct to just use send effectively? */
1123 /* FIXME: Should size include data w/ message or just message "header" */
1124 /* FIXME: Check return code */
1125 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
1126 0, 0, NULL, NULL, bAnsi );
1129 return DP_OK;
1132 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
1133 ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1134 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1136 *lpidGroup = DPID_UNKNOWN;
1138 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1139 lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
1142 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1143 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1144 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1146 *lpidGroup = DPID_UNKNOWN;
1148 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1149 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
1153 static void
1154 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1155 LPVOID lpData, DWORD dwDataSize )
1157 /* Clear out the data with this player */
1158 if( dwFlags & DPSET_LOCAL )
1160 if ( lpGData->dwLocalDataSize != 0 )
1162 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1163 lpGData->lpLocalData = NULL;
1164 lpGData->dwLocalDataSize = 0;
1167 else
1169 if( lpGData->dwRemoteDataSize != 0 )
1171 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1172 lpGData->lpRemoteData = NULL;
1173 lpGData->dwRemoteDataSize = 0;
1177 /* Reallocate for new data */
1178 if( lpData != NULL )
1180 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1181 sizeof( dwDataSize ) );
1182 CopyMemory( lpNewData, lpData, dwDataSize );
1184 if( dwFlags & DPSET_LOCAL )
1186 lpGData->lpLocalData = lpData;
1187 lpGData->dwLocalDataSize = dwDataSize;
1189 else
1191 lpGData->lpRemoteData = lpNewData;
1192 lpGData->dwRemoteDataSize = dwDataSize;
1198 /* This function will just create the storage for the new player. */
1199 static
1200 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1201 LPDPNAME lpName, DWORD dwFlags,
1202 HANDLE hEvent, BOOL bAnsi )
1204 lpPlayerData lpPData;
1206 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1208 /* Allocate the storage for the player and associate it with list element */
1209 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1210 if( lpPData == NULL )
1212 return NULL;
1215 /* Set the desired player ID */
1216 lpPData->dpid = *lpid;
1218 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1220 lpPData->dwFlags = dwFlags;
1222 /* If we were given an event handle, duplicate it */
1223 if( hEvent != 0 )
1225 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1226 GetCurrentProcess(), &lpPData->hEvent,
1227 0, FALSE, DUPLICATE_SAME_ACCESS )
1230 /* FIXME: Memory leak */
1231 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1235 /* Initialize the SP data section */
1236 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1238 TRACE( "Created player id 0x%08x\n", *lpid );
1240 if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1241 This->dp2->lpSessionDesc->dwCurrentPlayers++;
1243 return lpPData;
1246 /* Delete the contents of the DPNAME struct */
1247 static void
1248 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1250 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1251 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1254 /* This method assumes that all links to it are already deleted */
1255 static void
1256 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1258 lpPlayerList lpPList;
1260 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1262 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1264 if( lpPList == NULL )
1266 ERR( "DPID 0x%08x not found\n", dpid );
1267 return;
1270 /* Verify that this is the last reference to the data */
1271 if( --(lpPList->lpPData->uRef) )
1273 FIXME( "Why is this not the last reference to player?\n" );
1274 DebugBreak();
1277 /* Delete player */
1278 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1280 CloseHandle( lpPList->lpPData->hEvent );
1281 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1283 /* Delete Player List object */
1284 HeapFree( GetProcessHeap(), 0, lpPList );
1287 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1289 lpPlayerList lpPlayers;
1291 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1293 if(This->dp2->lpSysGroup == NULL)
1294 return NULL;
1296 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1298 return lpPlayers;
1301 /* Basic area for Dst must already be allocated */
1302 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1304 if( lpSrc == NULL )
1306 ZeroMemory( lpDst, sizeof( *lpDst ) );
1307 lpDst->dwSize = sizeof( *lpDst );
1308 return TRUE;
1311 if( lpSrc->dwSize != sizeof( *lpSrc) )
1313 return FALSE;
1316 /* Delete any existing pointers */
1317 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1318 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1320 /* Copy as required */
1321 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1323 if( bAnsi )
1325 if( lpSrc->u1.lpszShortNameA )
1327 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1328 strlen(lpSrc->u1.lpszShortNameA)+1 );
1329 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1331 if( lpSrc->u2.lpszLongNameA )
1333 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1334 strlen(lpSrc->u2.lpszLongNameA)+1 );
1335 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1338 else
1340 if( lpSrc->u1.lpszShortNameA )
1342 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1343 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1344 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1346 if( lpSrc->u2.lpszLongNameA )
1348 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1349 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1350 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1354 return TRUE;
1357 static void
1358 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1359 LPVOID lpData, DWORD dwDataSize )
1361 /* Clear out the data with this player */
1362 if( dwFlags & DPSET_LOCAL )
1364 if ( lpPData->dwLocalDataSize != 0 )
1366 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1367 lpPData->lpLocalData = NULL;
1368 lpPData->dwLocalDataSize = 0;
1371 else
1373 if( lpPData->dwRemoteDataSize != 0 )
1375 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1376 lpPData->lpRemoteData = NULL;
1377 lpPData->dwRemoteDataSize = 0;
1381 /* Reallocate for new data */
1382 if( lpData != NULL )
1384 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1385 sizeof( dwDataSize ) );
1386 CopyMemory( lpNewData, lpData, dwDataSize );
1388 if( dwFlags & DPSET_LOCAL )
1390 lpPData->lpLocalData = lpData;
1391 lpPData->dwLocalDataSize = dwDataSize;
1393 else
1395 lpPData->lpRemoteData = lpNewData;
1396 lpPData->dwRemoteDataSize = dwDataSize;
1402 static HRESULT DP_IF_CreatePlayer
1403 ( IDirectPlay2Impl* This,
1404 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1405 LPDPID lpidPlayer,
1406 LPDPNAME lpPlayerName,
1407 HANDLE hEvent,
1408 LPVOID lpData,
1409 DWORD dwDataSize,
1410 DWORD dwFlags,
1411 BOOL bAnsi )
1413 HRESULT hr = DP_OK;
1414 lpPlayerData lpPData;
1415 lpPlayerList lpPList;
1416 DWORD dwCreateFlags = 0;
1418 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1419 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1420 dwDataSize, dwFlags, bAnsi );
1421 if( This->dp2->connectionInitialized == NO_PROVIDER )
1423 return DPERR_UNINITIALIZED;
1426 if( dwFlags == 0 )
1428 dwFlags = DPPLAYER_SPECTATOR;
1431 if( lpidPlayer == NULL )
1433 return DPERR_INVALIDPARAMS;
1437 /* Determine the creation flags for the player. These will be passed
1438 * to the name server if requesting a player id and to the SP when
1439 * informing it of the player creation
1442 if( dwFlags & DPPLAYER_SERVERPLAYER )
1444 if( *lpidPlayer == DPID_SERVERPLAYER )
1446 /* Server player for the host interface */
1447 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1449 else if( *lpidPlayer == DPID_NAME_SERVER )
1451 /* Name server - master of everything */
1452 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1454 else
1456 /* Server player for a non host interface */
1457 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1461 if( lpMsgHdr == NULL )
1462 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1465 /* Verify we know how to handle all the flags */
1466 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1467 ( dwFlags & DPPLAYER_SPECTATOR )
1471 /* Assume non fatal failure */
1472 ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1475 /* If the name is not specified, we must provide one */
1476 if( *lpidPlayer == DPID_UNKNOWN )
1478 /* If we are the session master, we dish out the group/player ids */
1479 if( This->dp2->bHostInterface )
1481 *lpidPlayer = DP_NextObjectId();
1483 else
1485 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1487 if( FAILED(hr) )
1489 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1490 return hr;
1494 else
1496 /* FIXME: Would be nice to perhaps verify that we don't already have
1497 * this player.
1501 /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
1502 player total */
1503 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1504 hEvent, bAnsi );
1506 if( lpPData == NULL )
1508 return DPERR_CANTADDPLAYER;
1511 /* Create the list object and link it in */
1512 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1513 if( lpPList == NULL )
1515 FIXME( "Memory leak\n" );
1516 return DPERR_CANTADDPLAYER;
1519 lpPData->uRef = 1;
1520 lpPList->lpPData = lpPData;
1522 /* Add the player to the system group */
1523 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1525 /* Update the information and send it to all players in the session */
1526 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1528 /* Let the SP know that we've created this player */
1529 if( This->dp2->spData.lpCB->CreatePlayer )
1531 DPSP_CREATEPLAYERDATA data;
1533 data.idPlayer = *lpidPlayer;
1534 data.dwFlags = dwCreateFlags;
1535 data.lpSPMessageHeader = lpMsgHdr;
1536 data.lpISP = This->dp2->spData.lpISP;
1538 TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1539 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1541 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1544 if( FAILED(hr) )
1546 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1547 return hr;
1550 /* Now let the SP know that this player is a member of the system group */
1551 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1553 DPSP_ADDPLAYERTOGROUPDATA data;
1555 data.idPlayer = *lpidPlayer;
1556 data.idGroup = DPID_SYSTEM_GROUP;
1557 data.lpISP = This->dp2->spData.lpISP;
1559 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1561 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1564 if( FAILED(hr) )
1566 ERR( "Failed to add player to sys group with sp: %s\n",
1567 DPLAYX_HresultToString(hr) );
1568 return hr;
1571 #if 1
1572 if( This->dp2->bHostInterface == FALSE )
1574 /* Let the name server know about the creation of this player */
1575 /* FIXME: Is this only to be done for the creation of a server player or
1576 * is this used for regular players? If only for server players, move
1577 * this call to DP_SecureOpen(...);
1579 #if 0
1580 TRACE( "Sending message to self to get my addr\n" );
1581 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1582 #endif
1584 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1586 #else
1587 /* Inform all other peers of the creation of a new player. If there are
1588 * no peers keep this quiet.
1589 * Also, if this was a remote event, no need to rebroadcast it.
1591 if( ( lpMsgHdr == NULL ) &&
1592 This->dp2->lpSessionDesc &&
1593 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1595 DPMSG_CREATEPLAYERORGROUP msg;
1596 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1598 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1599 msg.dpId = *lpidPlayer;
1600 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1601 msg.lpData = lpData;
1602 msg.dwDataSize = dwDataSize;
1603 msg.dpnName = *lpPlayerName;
1604 msg.dpIdParent = DPID_NOPARENT_GROUP;
1605 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1607 /* FIXME: Correct to just use send effectively? */
1608 /* FIXME: Should size include data w/ message or just message "header" */
1609 /* FIXME: Check return code */
1610 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1611 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1613 #endif
1615 return hr;
1618 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1619 ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1620 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1622 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1624 if( lpidPlayer == NULL )
1626 return DPERR_INVALIDPARAMS;
1629 if( dwFlags & DPPLAYER_SERVERPLAYER )
1631 *lpidPlayer = DPID_SERVERPLAYER;
1633 else
1635 *lpidPlayer = DPID_UNKNOWN;
1638 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1639 lpData, dwDataSize, dwFlags, TRUE );
1642 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1643 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1644 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1646 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1648 if( lpidPlayer == NULL )
1650 return DPERR_INVALIDPARAMS;
1653 if( dwFlags & DPPLAYER_SERVERPLAYER )
1655 *lpidPlayer = DPID_SERVERPLAYER;
1657 else
1659 *lpidPlayer = DPID_UNKNOWN;
1662 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1663 lpData, dwDataSize, dwFlags, FALSE );
1666 static DPID DP_GetRemoteNextObjectId(void)
1668 FIXME( ":stub\n" );
1670 /* Hack solution */
1671 return DP_NextObjectId();
1674 static HRESULT DP_IF_DeletePlayerFromGroup
1675 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1676 DPID idPlayer, BOOL bAnsi )
1678 HRESULT hr = DP_OK;
1680 lpGroupData lpGData;
1681 lpPlayerList lpPList;
1683 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
1684 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1686 /* Find the group */
1687 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1689 return DPERR_INVALIDGROUP;
1692 /* Find the player */
1693 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1695 return DPERR_INVALIDPLAYER;
1698 /* Remove the player shortcut from the group */
1699 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1701 if( lpPList == NULL )
1703 return DPERR_INVALIDPLAYER;
1706 /* One less reference */
1707 lpPList->lpPData->uRef--;
1709 /* Delete the Player List element */
1710 HeapFree( GetProcessHeap(), 0, lpPList );
1712 /* Inform the SP if they care */
1713 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1715 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1717 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1719 data.idPlayer = idPlayer;
1720 data.idGroup = idGroup;
1721 data.lpISP = This->dp2->spData.lpISP;
1723 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1726 /* Need to send a DELETEPLAYERFROMGROUP message */
1727 FIXME( "Need to send a message\n" );
1729 return hr;
1732 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1733 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1735 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1736 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1739 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1740 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1742 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1743 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1746 typedef struct _DPRGOPContext
1748 IDirectPlay3Impl* This;
1749 BOOL bAnsi;
1750 DPID idGroup;
1751 } DPRGOPContext, *lpDPRGOPContext;
1753 static BOOL CALLBACK
1754 cbRemoveGroupOrPlayer(
1755 DPID dpId,
1756 DWORD dwPlayerType,
1757 LPCDPNAME lpName,
1758 DWORD dwFlags,
1759 LPVOID lpContext )
1761 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1763 TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1764 dpId, dwPlayerType, lpCtxt->idGroup );
1766 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1768 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1769 dpId )
1773 ERR( "Unable to delete group 0x%08x from group 0x%08x\n",
1774 dpId, lpCtxt->idGroup );
1777 else
1779 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1780 NULL, lpCtxt->idGroup,
1781 dpId, lpCtxt->bAnsi )
1785 ERR( "Unable to delete player 0x%08x from grp 0x%08x\n",
1786 dpId, lpCtxt->idGroup );
1790 return TRUE; /* Continue enumeration */
1793 static HRESULT DP_IF_DestroyGroup
1794 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1796 lpGroupData lpGData;
1797 DPRGOPContext context;
1799 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1800 This, lpMsgHdr, idGroup, bAnsi );
1802 /* Find the group */
1803 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1805 return DPERR_INVALIDPLAYER; /* yes player */
1808 context.This = (IDirectPlay3Impl*)This;
1809 context.bAnsi = bAnsi;
1810 context.idGroup = idGroup;
1812 /* Remove all players that this group has */
1813 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1814 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1816 /* Remove all links to groups that this group has since this is dp3 */
1817 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1818 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1820 /* Remove this group from the parent group - if it has one */
1821 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1822 ( lpGData->parent != DPID_SYSTEM_GROUP )
1825 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1826 idGroup );
1829 /* Now delete this group data and list from the system group */
1830 DP_DeleteGroup( This, idGroup );
1832 /* Let the SP know that we've destroyed this group */
1833 if( This->dp2->spData.lpCB->DeleteGroup )
1835 DPSP_DELETEGROUPDATA data;
1837 FIXME( "data.dwFlags is incorrect\n" );
1839 data.idGroup = idGroup;
1840 data.dwFlags = 0;
1841 data.lpISP = This->dp2->spData.lpISP;
1843 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1846 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1848 return DP_OK;
1851 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1852 ( LPDIRECTPLAY2A iface, DPID idGroup )
1854 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1855 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1858 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1859 ( LPDIRECTPLAY2 iface, DPID idGroup )
1861 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1862 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1865 typedef struct _DPFAGContext
1867 IDirectPlay2Impl* This;
1868 DPID idPlayer;
1869 BOOL bAnsi;
1870 } DPFAGContext, *lpDPFAGContext;
1872 static HRESULT DP_IF_DestroyPlayer
1873 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1875 DPFAGContext cbContext;
1877 FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1878 This, lpMsgHdr, idPlayer, bAnsi );
1880 if( This->dp2->connectionInitialized == NO_PROVIDER )
1882 return DPERR_UNINITIALIZED;
1885 if( DP_FindPlayer( This, idPlayer ) == NULL )
1887 return DPERR_INVALIDPLAYER;
1890 /* FIXME: If the player is remote, we must be the host to delete this */
1892 cbContext.This = This;
1893 cbContext.idPlayer = idPlayer;
1894 cbContext.bAnsi = bAnsi;
1896 /* Find each group and call DeletePlayerFromGroup if the player is a
1897 member of the group */
1898 DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
1899 (LPVOID)&cbContext, DPENUMGROUPS_ALL, bAnsi );
1901 /* Now delete player and player list from the sys group */
1902 DP_DeletePlayer( This, idPlayer );
1904 /* Let the SP know that we've destroyed this group */
1905 if( This->dp2->spData.lpCB->DeletePlayer )
1907 DPSP_DELETEPLAYERDATA data;
1909 FIXME( "data.dwFlags is incorrect\n" );
1911 data.idPlayer = idPlayer;
1912 data.dwFlags = 0;
1913 data.lpISP = This->dp2->spData.lpISP;
1915 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1918 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1920 return DP_OK;
1923 static BOOL CALLBACK
1924 cbDeletePlayerFromAllGroups(
1925 DPID dpId,
1926 DWORD dwPlayerType,
1927 LPCDPNAME lpName,
1928 DWORD dwFlags,
1929 LPVOID lpContext )
1931 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1933 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1935 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
1936 lpCtxt->bAnsi );
1938 /* Enumerate all groups in this group since this will normally only
1939 * be called for top level groups
1941 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
1942 dpId, NULL,
1943 cbDeletePlayerFromAllGroups,
1944 lpContext, DPENUMGROUPS_ALL,
1945 lpCtxt->bAnsi );
1948 else
1950 ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
1953 return TRUE;
1956 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
1957 ( LPDIRECTPLAY2A iface, DPID idPlayer )
1959 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1960 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1963 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1964 ( LPDIRECTPLAY2 iface, DPID idPlayer )
1966 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1967 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1970 static HRESULT DP_IF_EnumGroupPlayers
1971 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1972 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1973 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1975 lpGroupData lpGData;
1976 lpPlayerList lpPList;
1978 FIXME("(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
1979 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1980 lpContext, dwFlags, bAnsi );
1982 if( This->dp2->connectionInitialized == NO_PROVIDER )
1984 return DPERR_UNINITIALIZED;
1987 /* Find the group */
1988 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1990 return DPERR_INVALIDGROUP;
1993 if( DPQ_IS_EMPTY( lpGData->players ) )
1995 return DP_OK;
1998 lpPList = DPQ_FIRST( lpGData->players );
2000 /* Walk the players in this group */
2001 for( ;; )
2003 /* We do not enum the name server or app server as they are of no
2004 * consequence to the end user.
2006 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
2007 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
2011 /* FIXME: Need to add stuff for dwFlags checking */
2013 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
2014 &lpPList->lpPData->name,
2015 lpPList->lpPData->dwFlags,
2016 lpContext )
2019 /* User requested break */
2020 return DP_OK;
2024 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
2026 break;
2029 lpPList = DPQ_NEXT( lpPList->players );
2032 return DP_OK;
2035 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
2036 ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
2037 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2038 LPVOID lpContext, DWORD dwFlags )
2040 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2041 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2042 lpEnumPlayersCallback2, lpContext,
2043 dwFlags, TRUE );
2046 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
2047 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
2048 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2049 LPVOID lpContext, DWORD dwFlags )
2051 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2052 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2053 lpEnumPlayersCallback2, lpContext,
2054 dwFlags, FALSE );
2057 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2058 static HRESULT DP_IF_EnumGroups
2059 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2060 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2061 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2063 return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2064 DPID_SYSTEM_GROUP, lpguidInstance,
2065 lpEnumPlayersCallback2, lpContext,
2066 dwFlags, bAnsi );
2069 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2070 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2071 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2072 LPVOID lpContext, DWORD dwFlags )
2074 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2075 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2076 lpContext, dwFlags, TRUE );
2079 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2080 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2081 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2082 LPVOID lpContext, DWORD dwFlags )
2084 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2085 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2086 lpContext, dwFlags, FALSE );
2089 static HRESULT DP_IF_EnumPlayers
2090 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2091 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2092 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2094 return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
2095 lpEnumPlayersCallback2, lpContext,
2096 dwFlags, bAnsi );
2099 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2100 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2101 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2102 LPVOID lpContext, DWORD dwFlags )
2104 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2105 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2106 lpContext, dwFlags, TRUE );
2109 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2110 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2111 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2112 LPVOID lpContext, DWORD dwFlags )
2114 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2115 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2116 lpContext, dwFlags, FALSE );
2119 /* This function should call the registered callback function that the user
2120 passed into EnumSessions for each entry available.
2122 static void DP_InvokeEnumSessionCallbacks
2123 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2124 LPVOID lpNSInfo,
2125 DWORD dwTimeout,
2126 LPVOID lpContext )
2128 LPDPSESSIONDESC2 lpSessionDesc;
2130 FIXME( ": not checking for conditions\n" );
2132 /* Not sure if this should be pruning but it's convenient */
2133 NS_PruneSessionCache( lpNSInfo );
2135 NS_ResetSessionEnumeration( lpNSInfo );
2137 /* Enumerate all sessions */
2138 /* FIXME: Need to indicate ANSI */
2139 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2141 TRACE( "EnumSessionsCallback2 invoked\n" );
2142 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2144 return;
2148 /* Invoke one last time to indicate that there is no more to come */
2149 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2152 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2154 EnumSessionAsyncCallbackData* data = (EnumSessionAsyncCallbackData*)lpContext;
2155 HANDLE hSuicideRequest = data->hSuicideRequest;
2156 DWORD dwTimeout = data->dwTimeout;
2158 TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
2160 for( ;; )
2162 HRESULT hr;
2164 /* Sleep up to dwTimeout waiting for request to terminate thread */
2165 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2167 TRACE( "Thread terminating on terminate request\n" );
2168 break;
2171 /* Now resend the enum request */
2172 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2173 data->dwEnumSessionFlags,
2174 data->lpSpData );
2176 if( FAILED(hr) )
2178 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2179 /* FIXME: Should we kill this thread? How to inform the main thread? */
2184 TRACE( "Thread terminating\n" );
2186 /* Clean up the thread data */
2187 CloseHandle( hSuicideRequest );
2188 HeapFree( GetProcessHeap(), 0, lpContext );
2190 /* FIXME: Need to have some notification to main app thread that this is
2191 * dead. It would serve two purposes. 1) allow sync on termination
2192 * so that we don't actually send something to ourselves when we
2193 * become name server (race condition) and 2) so that if we die
2194 * abnormally something else will be able to tell.
2197 return 1;
2200 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
2202 /* Does a thread exist? If so we were doing an async enum session */
2203 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2205 TRACE( "Killing EnumSession thread %p\n",
2206 This->dp2->hEnumSessionThread );
2208 /* Request that the thread kill itself nicely */
2209 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2210 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2212 /* We no longer need to know about the thread */
2213 CloseHandle( This->dp2->hEnumSessionThread );
2215 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2219 static HRESULT DP_IF_EnumSessions
2220 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2221 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2222 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2224 HRESULT hr = DP_OK;
2226 TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x,%u)\n",
2227 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2228 bAnsi );
2229 if( This->dp2->connectionInitialized == NO_PROVIDER )
2231 return DPERR_UNINITIALIZED;
2234 /* Can't enumerate if the interface is already open */
2235 if( This->dp2->bConnectionOpen )
2237 return DPERR_GENERIC;
2240 #if 1
2241 /* The loading of a lobby provider _seems_ to require a backdoor loading
2242 * of the service provider to also associate with this DP object. This is
2243 * because the app doesn't seem to have to call EnumConnections and
2244 * InitializeConnection for the SP before calling this method. As such
2245 * we'll do their dirty work for them with a quick hack so as to always
2246 * load the TCP/IP service provider.
2248 * The correct solution would seem to involve creating a dialog box which
2249 * contains the possible SPs. These dialog boxes most likely follow SDK
2250 * examples.
2252 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2254 LPVOID lpConnection;
2255 DWORD dwSize;
2257 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2259 if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2261 ERR( "Can't build compound addr\n" );
2262 return DPERR_GENERIC;
2265 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2266 0, bAnsi );
2267 if( FAILED(hr) )
2269 return hr;
2272 /* Free up the address buffer */
2273 HeapFree( GetProcessHeap(), 0, lpConnection );
2275 /* The SP is now initialized */
2276 This->dp2->bSPInitialized = TRUE;
2278 #endif
2281 /* Use the service provider default? */
2282 if( dwTimeout == 0 )
2284 DPCAPS spCaps;
2285 spCaps.dwSize = sizeof( spCaps );
2287 DP_IF_GetCaps( This, &spCaps, 0 );
2288 dwTimeout = spCaps.dwTimeout;
2290 /* The service provider doesn't provide one either! */
2291 if( dwTimeout == 0 )
2293 /* Provide the TCP/IP default */
2294 dwTimeout = DPMSG_WAIT_5_SECS;
2298 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2300 DP_KillEnumSessionThread( This );
2301 return hr;
2304 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2306 /* Enumerate everything presently in the local session cache */
2307 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2308 This->dp2->lpNameServerData, dwTimeout,
2309 lpContext );
2311 if( This->dp2->dwEnumSessionLock != 0 )
2312 return DPERR_CONNECTING;
2314 /* See if we've already created a thread to service this interface */
2315 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2317 DWORD dwThreadId;
2318 This->dp2->dwEnumSessionLock++;
2320 /* Send the first enum request inline since the user may cancel a dialog
2321 * if one is presented. Also, may also have a connecting return code.
2323 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2324 dwFlags, &This->dp2->spData );
2326 if( SUCCEEDED(hr) )
2328 EnumSessionAsyncCallbackData* lpData
2329 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2330 /* FIXME: need to kill the thread on object deletion */
2331 lpData->lpSpData = &This->dp2->spData;
2333 lpData->requestGuid = lpsd->guidApplication;
2334 lpData->dwEnumSessionFlags = dwFlags;
2335 lpData->dwTimeout = dwTimeout;
2337 This->dp2->hKillEnumSessionThreadEvent =
2338 CreateEventW( NULL, TRUE, FALSE, NULL );
2340 if( !DuplicateHandle( GetCurrentProcess(),
2341 This->dp2->hKillEnumSessionThreadEvent,
2342 GetCurrentProcess(),
2343 &lpData->hSuicideRequest,
2344 0, FALSE, DUPLICATE_SAME_ACCESS )
2347 ERR( "Can't duplicate thread killing handle\n" );
2350 TRACE( ": creating EnumSessionsRequest thread\n" );
2352 This->dp2->hEnumSessionThread = CreateThread( NULL,
2354 DP_EnumSessionsSendAsyncRequestThread,
2355 lpData,
2357 &dwThreadId );
2359 This->dp2->dwEnumSessionLock--;
2362 else
2364 /* Invalidate the session cache for the interface */
2365 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2367 /* Send the broadcast for session enumeration */
2368 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2369 dwFlags,
2370 &This->dp2->spData );
2373 SleepEx( dwTimeout, FALSE );
2375 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2376 This->dp2->lpNameServerData, dwTimeout,
2377 lpContext );
2380 return hr;
2383 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2384 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2385 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2386 LPVOID lpContext, DWORD dwFlags )
2388 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2389 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2390 lpContext, dwFlags, TRUE );
2393 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2394 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2395 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2396 LPVOID lpContext, DWORD dwFlags )
2398 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2399 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2400 lpContext, dwFlags, FALSE );
2403 static HRESULT DP_IF_GetPlayerCaps
2404 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2405 DWORD dwFlags )
2407 DPSP_GETCAPSDATA data;
2409 TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
2411 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2413 return DPERR_UNINITIALIZED;
2416 /* Query the service provider */
2417 data.idPlayer = idPlayer;
2418 data.dwFlags = dwFlags;
2419 data.lpCaps = lpDPCaps;
2420 data.lpISP = This->dp2->spData.lpISP;
2422 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2425 static HRESULT DP_IF_GetCaps
2426 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2428 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2431 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2432 ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2434 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2435 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2438 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2439 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2441 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2442 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2445 static HRESULT DP_IF_GetGroupData
2446 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2447 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2449 lpGroupData lpGData;
2450 DWORD dwRequiredBufferSize;
2451 LPVOID lpCopyDataFrom;
2453 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2454 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2456 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2458 return DPERR_INVALIDGROUP;
2461 /* How much buffer is required? */
2462 if( dwFlags & DPSET_LOCAL )
2464 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2465 lpCopyDataFrom = lpGData->lpLocalData;
2467 else
2469 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2470 lpCopyDataFrom = lpGData->lpRemoteData;
2473 /* Is the user requesting to know how big a buffer is required? */
2474 if( ( lpData == NULL ) ||
2475 ( *lpdwDataSize < dwRequiredBufferSize )
2478 *lpdwDataSize = dwRequiredBufferSize;
2479 return DPERR_BUFFERTOOSMALL;
2482 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2484 return DP_OK;
2487 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2488 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2489 LPDWORD lpdwDataSize, DWORD dwFlags )
2491 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2492 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2493 dwFlags, TRUE );
2496 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2497 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2498 LPDWORD lpdwDataSize, DWORD dwFlags )
2500 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2501 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2502 dwFlags, FALSE );
2505 static HRESULT DP_IF_GetGroupName
2506 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2507 LPDWORD lpdwDataSize, BOOL bAnsi )
2509 lpGroupData lpGData;
2510 LPDPNAME lpName = (LPDPNAME)lpData;
2511 DWORD dwRequiredDataSize;
2513 FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2514 This, idGroup, lpData, lpdwDataSize, bAnsi );
2516 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2518 return DPERR_INVALIDGROUP;
2521 dwRequiredDataSize = lpGData->name.dwSize;
2523 if( lpGData->name.u1.lpszShortNameA )
2525 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2528 if( lpGData->name.u2.lpszLongNameA )
2530 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2533 if( ( lpData == NULL ) ||
2534 ( *lpdwDataSize < dwRequiredDataSize )
2537 *lpdwDataSize = dwRequiredDataSize;
2538 return DPERR_BUFFERTOOSMALL;
2541 /* Copy the structure */
2542 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2544 if( lpGData->name.u1.lpszShortNameA )
2546 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2547 lpGData->name.u1.lpszShortNameA );
2549 else
2551 lpName->u1.lpszShortNameA = NULL;
2554 if( lpGData->name.u1.lpszShortNameA )
2556 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2557 lpGData->name.u2.lpszLongNameA );
2559 else
2561 lpName->u2.lpszLongNameA = NULL;
2564 return DP_OK;
2567 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2568 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2569 LPDWORD lpdwDataSize )
2571 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2572 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2575 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2576 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2577 LPDWORD lpdwDataSize )
2579 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2580 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2583 static HRESULT DP_IF_GetMessageCount
2584 ( IDirectPlay2Impl* This, DPID idPlayer,
2585 LPDWORD lpdwCount, BOOL bAnsi )
2587 FIXME("(%p)->(0x%08x,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2588 return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2589 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2590 bAnsi );
2593 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2594 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2596 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2597 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2600 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2601 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2603 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2604 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2607 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2608 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2610 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2611 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2612 return DP_OK;
2615 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2616 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2618 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2619 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2620 return DP_OK;
2623 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2624 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2625 DWORD dwFlags )
2627 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2628 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2631 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2632 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2633 DWORD dwFlags )
2635 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2636 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2639 static HRESULT DP_IF_GetPlayerData
2640 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2641 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2643 lpPlayerList lpPList;
2644 DWORD dwRequiredBufferSize;
2645 LPVOID lpCopyDataFrom;
2647 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2648 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2650 if( This->dp2->connectionInitialized == NO_PROVIDER )
2652 return DPERR_UNINITIALIZED;
2655 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2657 return DPERR_INVALIDPLAYER;
2660 /* How much buffer is required? */
2661 if( dwFlags & DPSET_LOCAL )
2663 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2664 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2666 else
2668 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2669 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2672 /* Is the user requesting to know how big a buffer is required? */
2673 if( ( lpData == NULL ) ||
2674 ( *lpdwDataSize < dwRequiredBufferSize )
2677 *lpdwDataSize = dwRequiredBufferSize;
2678 return DPERR_BUFFERTOOSMALL;
2681 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2683 return DP_OK;
2686 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2687 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2688 LPDWORD lpdwDataSize, DWORD dwFlags )
2690 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2691 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2692 dwFlags, TRUE );
2695 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2696 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2697 LPDWORD lpdwDataSize, DWORD dwFlags )
2699 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2700 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2701 dwFlags, FALSE );
2704 static HRESULT DP_IF_GetPlayerName
2705 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2706 LPDWORD lpdwDataSize, BOOL bAnsi )
2708 lpPlayerList lpPList;
2709 LPDPNAME lpName = (LPDPNAME)lpData;
2710 DWORD dwRequiredDataSize;
2712 FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2713 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2715 if( This->dp2->connectionInitialized == NO_PROVIDER )
2717 return DPERR_UNINITIALIZED;
2720 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2722 return DPERR_INVALIDPLAYER;
2725 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2727 if( lpPList->lpPData->name.u1.lpszShortNameA )
2729 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2732 if( lpPList->lpPData->name.u2.lpszLongNameA )
2734 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2737 if( ( lpData == NULL ) ||
2738 ( *lpdwDataSize < dwRequiredDataSize )
2741 *lpdwDataSize = dwRequiredDataSize;
2742 return DPERR_BUFFERTOOSMALL;
2745 /* Copy the structure */
2746 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2748 if( lpPList->lpPData->name.u1.lpszShortNameA )
2750 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2751 lpPList->lpPData->name.u1.lpszShortNameA );
2753 else
2755 lpName->u1.lpszShortNameA = NULL;
2758 if( lpPList->lpPData->name.u1.lpszShortNameA )
2760 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2761 lpPList->lpPData->name.u2.lpszLongNameA );
2763 else
2765 lpName->u2.lpszLongNameA = NULL;
2768 return DP_OK;
2771 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2772 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2773 LPDWORD lpdwDataSize )
2775 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2776 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2779 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2780 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2781 LPDWORD lpdwDataSize )
2783 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2784 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2787 static HRESULT DP_GetSessionDesc
2788 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2789 BOOL bAnsi )
2791 DWORD dwRequiredSize;
2793 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2795 if( This->dp2->connectionInitialized == NO_PROVIDER )
2797 return DPERR_UNINITIALIZED;
2800 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2802 return DPERR_INVALIDPARAMS;
2805 /* FIXME: Get from This->dp2->lpSessionDesc */
2806 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2808 if ( ( lpData == NULL ) ||
2809 ( *lpdwDataSize < dwRequiredSize )
2812 *lpdwDataSize = dwRequiredSize;
2813 return DPERR_BUFFERTOOSMALL;
2816 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2818 return DP_OK;
2821 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2822 ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2824 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2825 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2828 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2829 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2831 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2832 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2835 /* Intended only for COM compatibility. Always returns an error. */
2836 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2837 ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2839 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2840 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2841 return DPERR_ALREADYINITIALIZED;
2844 /* Intended only for COM compatibility. Always returns an error. */
2845 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2846 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2848 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2849 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2850 return DPERR_ALREADYINITIALIZED;
2854 static HRESULT DP_SecureOpen
2855 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2856 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2857 BOOL bAnsi )
2859 HRESULT hr = DP_OK;
2861 FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2862 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2864 if( This->dp2->connectionInitialized == NO_PROVIDER )
2866 return DPERR_UNINITIALIZED;
2869 if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
2871 TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
2872 return DPERR_INVALIDPARAMS;
2875 if( This->dp2->bConnectionOpen )
2877 TRACE( ": rejecting already open connection.\n" );
2878 return DPERR_ALREADYINITIALIZED;
2881 /* If we're enumerating, kill the thread */
2882 DP_KillEnumSessionThread( This );
2884 if( dwFlags & DPOPEN_CREATE )
2886 /* Rightoo - this computer is the host and the local computer needs to be
2887 the name server so that others can join this session */
2888 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2890 This->dp2->bHostInterface = TRUE;
2892 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2893 if( FAILED( hr ) )
2895 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2896 return hr;
2900 /* Invoke the conditional callback for the service provider */
2901 if( This->dp2->spData.lpCB->Open )
2903 DPSP_OPENDATA data;
2905 FIXME( "Not all data fields are correct. Need new parameter\n" );
2907 data.bCreate = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
2908 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2909 : NS_GetNSAddr( This->dp2->lpNameServerData );
2910 data.lpISP = This->dp2->spData.lpISP;
2911 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
2912 data.dwOpenFlags = dwFlags;
2913 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2915 hr = (*This->dp2->spData.lpCB->Open)(&data);
2916 if( FAILED( hr ) )
2918 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2919 return hr;
2924 /* Create the system group of which everything is a part of */
2925 DPID systemGroup = DPID_SYSTEM_GROUP;
2927 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2928 NULL, 0, 0, TRUE );
2932 if( dwFlags & DPOPEN_JOIN )
2934 DPID dpidServerId = DPID_UNKNOWN;
2936 /* Create the server player for this interface. This way we can receive
2937 * messages for this session.
2939 /* FIXME: I suppose that we should be setting an event for a receive
2940 * type of thing. That way the messaging thread could know to wake
2941 * up. DPlay would then trigger the hEvent for the player the
2942 * message is directed to.
2944 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2946 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2949 else if( dwFlags & DPOPEN_CREATE )
2951 DPID dpidNameServerId = DPID_NAME_SERVER;
2953 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2954 0, DPPLAYER_SERVERPLAYER, bAnsi );
2957 if( FAILED(hr) )
2959 ERR( "Couldn't create name server/system player: %s\n",
2960 DPLAYX_HresultToString(hr) );
2963 return hr;
2966 static HRESULT WINAPI DirectPlay2AImpl_Open
2967 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2969 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2970 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2971 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
2974 static HRESULT WINAPI DirectPlay2WImpl_Open
2975 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2977 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2978 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2979 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
2982 static HRESULT DP_IF_Receive
2983 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2984 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2986 LPDPMSG lpMsg = NULL;
2988 FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
2989 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2991 if( This->dp2->connectionInitialized == NO_PROVIDER )
2993 return DPERR_UNINITIALIZED;
2996 if( dwFlags == 0 )
2998 dwFlags = DPRECEIVE_ALL;
3001 /* If the lpData is NULL, we must be peeking the message */
3002 if( ( lpData == NULL ) &&
3003 !( dwFlags & DPRECEIVE_PEEK )
3006 return DPERR_INVALIDPARAMS;
3009 if( dwFlags & DPRECEIVE_ALL )
3011 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
3013 if( !( dwFlags & DPRECEIVE_PEEK ) )
3015 FIXME( "Remove from queue\n" );
3018 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
3019 ( dwFlags & DPRECEIVE_FROMPLAYER )
3022 FIXME( "Find matching message 0x%08x\n", dwFlags );
3024 else
3026 ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
3029 if( lpMsg == NULL )
3031 return DPERR_NOMESSAGES;
3034 /* Copy into the provided buffer */
3035 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
3037 return DP_OK;
3040 static HRESULT WINAPI DirectPlay2AImpl_Receive
3041 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
3042 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3044 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3045 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3046 lpData, lpdwDataSize, TRUE );
3049 static HRESULT WINAPI DirectPlay2WImpl_Receive
3050 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
3051 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3053 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3054 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3055 lpData, lpdwDataSize, FALSE );
3058 static HRESULT WINAPI DirectPlay2AImpl_Send
3059 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3061 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3062 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3063 0, 0, NULL, NULL, TRUE );
3066 static HRESULT WINAPI DirectPlay2WImpl_Send
3067 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3069 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3070 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3071 0, 0, NULL, NULL, FALSE );
3074 static HRESULT DP_IF_SetGroupData
3075 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3076 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3078 lpGroupData lpGData;
3080 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3081 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3083 /* Parameter check */
3084 if( ( lpData == NULL ) &&
3085 ( dwDataSize != 0 )
3088 return DPERR_INVALIDPARAMS;
3091 /* Find the pointer to the data for this player */
3092 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3094 return DPERR_INVALIDOBJECT;
3097 if( !(dwFlags & DPSET_LOCAL) )
3099 FIXME( "Was this group created by this interface?\n" );
3100 /* FIXME: If this is a remote update need to allow it but not
3101 * send a message.
3105 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3107 /* FIXME: Only send a message if this group is local to the session otherwise
3108 * it will have been rejected above
3110 if( !(dwFlags & DPSET_LOCAL) )
3112 FIXME( "Send msg?\n" );
3115 return DP_OK;
3118 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3119 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3120 DWORD dwDataSize, DWORD dwFlags )
3122 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3123 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3126 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3127 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3128 DWORD dwDataSize, DWORD dwFlags )
3130 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3131 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3134 static HRESULT DP_IF_SetGroupName
3135 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3136 DWORD dwFlags, BOOL bAnsi )
3138 lpGroupData lpGData;
3140 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3141 lpGroupName, dwFlags, bAnsi );
3143 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3145 return DPERR_INVALIDGROUP;
3148 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3150 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3151 FIXME( "Message not sent and dwFlags ignored\n" );
3153 return DP_OK;
3156 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3157 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3158 DWORD dwFlags )
3160 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3161 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3164 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3165 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3166 DWORD dwFlags )
3168 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3169 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3172 static HRESULT DP_IF_SetPlayerData
3173 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3174 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3176 lpPlayerList lpPList;
3178 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3179 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3181 if( This->dp2->connectionInitialized == NO_PROVIDER )
3183 return DPERR_UNINITIALIZED;
3186 /* Parameter check */
3187 if( ( lpData == NULL ) &&
3188 ( dwDataSize != 0 )
3191 return DPERR_INVALIDPARAMS;
3194 /* Find the pointer to the data for this player */
3195 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3197 return DPERR_INVALIDPLAYER;
3200 if( !(dwFlags & DPSET_LOCAL) )
3202 FIXME( "Was this group created by this interface?\n" );
3203 /* FIXME: If this is a remote update need to allow it but not
3204 * send a message.
3208 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3210 if( !(dwFlags & DPSET_LOCAL) )
3212 FIXME( "Send msg?\n" );
3215 return DP_OK;
3218 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3219 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3220 DWORD dwDataSize, DWORD dwFlags )
3222 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3223 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3224 dwFlags, TRUE );
3227 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3228 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3229 DWORD dwDataSize, DWORD dwFlags )
3231 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3232 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3233 dwFlags, FALSE );
3236 static HRESULT DP_IF_SetPlayerName
3237 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3238 DWORD dwFlags, BOOL bAnsi )
3240 lpPlayerList lpPList;
3242 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3243 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3245 if( This->dp2->connectionInitialized == NO_PROVIDER )
3247 return DPERR_UNINITIALIZED;
3250 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3252 return DPERR_INVALIDGROUP;
3255 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3257 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3258 FIXME( "Message not sent and dwFlags ignored\n" );
3260 return DP_OK;
3263 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3264 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3265 DWORD dwFlags )
3267 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3268 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3271 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3272 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3273 DWORD dwFlags )
3275 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3276 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3279 static HRESULT DP_SetSessionDesc
3280 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3281 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3283 DWORD dwRequiredSize;
3284 LPDPSESSIONDESC2 lpTempSessDesc;
3286 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3287 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3289 if( This->dp2->connectionInitialized == NO_PROVIDER )
3291 return DPERR_UNINITIALIZED;
3294 if( dwFlags )
3296 return DPERR_INVALIDPARAMS;
3299 /* Only the host is allowed to update the session desc */
3300 if( !This->dp2->bHostInterface )
3302 return DPERR_ACCESSDENIED;
3305 /* FIXME: Copy into This->dp2->lpSessionDesc */
3306 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3307 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3309 if( lpTempSessDesc == NULL )
3311 return DPERR_OUTOFMEMORY;
3314 /* Free the old */
3315 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3317 This->dp2->lpSessionDesc = lpTempSessDesc;
3318 /* Set the new */
3319 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3320 if( bInitial )
3322 /*Initializing session GUID*/
3323 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3325 /* If this is an external invocation of the interface, we should be
3326 * letting everyone know that things have changed. Otherwise this is
3327 * just an initialization and it doesn't need to be propagated.
3329 if( !bInitial )
3331 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3334 return DP_OK;
3337 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3338 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3340 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3341 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3344 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3345 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3347 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3348 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3351 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3352 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3354 DWORD dwSize = 0;
3356 if( lpSessDesc == NULL )
3358 /* Hmmm..don't need any size? */
3359 ERR( "NULL lpSessDesc\n" );
3360 return dwSize;
3363 dwSize += sizeof( *lpSessDesc );
3365 if( bAnsi )
3367 if( lpSessDesc->u1.lpszSessionNameA )
3369 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3372 if( lpSessDesc->u2.lpszPasswordA )
3374 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3377 else /* UNICODE */
3379 if( lpSessDesc->u1.lpszSessionName )
3381 dwSize += sizeof( WCHAR ) *
3382 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3385 if( lpSessDesc->u2.lpszPassword )
3387 dwSize += sizeof( WCHAR ) *
3388 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3392 return dwSize;
3395 /* Assumes that contiguous buffers are already allocated. */
3396 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3397 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3399 BYTE* lpStartOfFreeSpace;
3401 if( lpSessionDest == NULL )
3403 ERR( "NULL lpSessionDest\n" );
3404 return;
3407 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3409 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3411 if( bAnsi )
3413 if( lpSessionSrc->u1.lpszSessionNameA )
3415 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3416 lpSessionDest->u1.lpszSessionNameA );
3417 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3418 lpStartOfFreeSpace +=
3419 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3422 if( lpSessionSrc->u2.lpszPasswordA )
3424 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3425 lpSessionDest->u2.lpszPasswordA );
3426 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3427 lpStartOfFreeSpace +=
3428 lstrlenA( lpSessionDest->u2.lpszPasswordA ) + 1;
3431 else /* UNICODE */
3433 if( lpSessionSrc->u1.lpszSessionName )
3435 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3436 lpSessionDest->u1.lpszSessionName );
3437 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3438 lpStartOfFreeSpace += sizeof(WCHAR) *
3439 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3442 if( lpSessionSrc->u2.lpszPassword )
3444 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3445 lpSessionDest->u2.lpszPassword );
3446 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3447 lpStartOfFreeSpace += sizeof(WCHAR) *
3448 ( lstrlenW( lpSessionDest->u2.lpszPassword ) + 1 );
3454 static HRESULT DP_IF_AddGroupToGroup
3455 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3457 lpGroupData lpGData;
3458 lpGroupList lpNewGList;
3460 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3462 if( This->dp2->connectionInitialized == NO_PROVIDER )
3464 return DPERR_UNINITIALIZED;
3467 if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3469 return DPERR_INVALIDGROUP;
3472 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3474 return DPERR_INVALIDGROUP;
3477 /* Create a player list (ie "shortcut" ) */
3478 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3479 if( lpNewGList == NULL )
3481 return DPERR_CANTADDPLAYER;
3484 /* Add the shortcut */
3485 lpGData->uRef++;
3486 lpNewGList->lpGData = lpGData;
3488 /* Add the player to the list of players for this group */
3489 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3491 /* Send a ADDGROUPTOGROUP message */
3492 FIXME( "Not sending message\n" );
3494 return DP_OK;
3497 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3498 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3500 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3501 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3504 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3505 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3507 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3508 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3511 static HRESULT DP_IF_CreateGroupInGroup
3512 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3513 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3514 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3516 lpGroupData lpGParentData;
3517 lpGroupList lpGList;
3518 lpGroupData lpGData;
3520 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3521 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3522 dwDataSize, dwFlags, bAnsi );
3524 if( This->dp2->connectionInitialized == NO_PROVIDER )
3526 return DPERR_UNINITIALIZED;
3529 /* Verify that the specified parent is valid */
3530 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3531 idParentGroup ) ) == NULL
3534 return DPERR_INVALIDGROUP;
3537 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3538 dwFlags, idParentGroup, bAnsi );
3540 if( lpGData == NULL )
3542 return DPERR_CANTADDPLAYER; /* yes player not group */
3545 /* Something else is referencing this data */
3546 lpGData->uRef++;
3548 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3550 /* The list has now been inserted into the interface group list. We now
3551 need to put a "shortcut" to this group in the parent group */
3552 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3553 if( lpGList == NULL )
3555 FIXME( "Memory leak\n" );
3556 return DPERR_CANTADDPLAYER; /* yes player not group */
3559 lpGList->lpGData = lpGData;
3561 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3563 /* Let the SP know that we've created this group */
3564 if( This->dp2->spData.lpCB->CreateGroup )
3566 DPSP_CREATEGROUPDATA data;
3568 TRACE( "Calling SP CreateGroup\n" );
3570 data.idGroup = *lpidGroup;
3571 data.dwFlags = dwFlags;
3572 data.lpSPMessageHeader = lpMsgHdr;
3573 data.lpISP = This->dp2->spData.lpISP;
3575 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3578 /* Inform all other peers of the creation of a new group. If there are
3579 * no peers keep this quiet.
3581 if( This->dp2->lpSessionDesc &&
3582 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3584 DPMSG_CREATEPLAYERORGROUP msg;
3586 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3587 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3588 msg.dpId = *lpidGroup;
3589 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3590 msg.lpData = lpData;
3591 msg.dwDataSize = dwDataSize;
3592 msg.dpnName = *lpGroupName;
3594 /* FIXME: Correct to just use send effectively? */
3595 /* FIXME: Should size include data w/ message or just message "header" */
3596 /* FIXME: Check return code */
3597 DP_SendEx( (IDirectPlay2Impl*)This,
3598 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3599 0, 0, NULL, NULL, bAnsi );
3602 return DP_OK;
3605 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3606 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3607 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3608 DWORD dwFlags )
3610 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3612 *lpidGroup = DPID_UNKNOWN;
3614 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3615 lpGroupName, lpData, dwDataSize, dwFlags,
3616 TRUE );
3619 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3620 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3621 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3622 DWORD dwFlags )
3624 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3626 *lpidGroup = DPID_UNKNOWN;
3628 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3629 lpGroupName, lpData, dwDataSize,
3630 dwFlags, FALSE );
3633 static HRESULT DP_IF_DeleteGroupFromGroup
3634 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3636 lpGroupList lpGList;
3637 lpGroupData lpGParentData;
3639 TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3641 /* Is the parent group valid? */
3642 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3644 return DPERR_INVALIDGROUP;
3647 /* Remove the group from the parent group queue */
3648 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3650 if( lpGList == NULL )
3652 return DPERR_INVALIDGROUP;
3655 /* Decrement the ref count */
3656 lpGList->lpGData->uRef--;
3658 /* Free up the list item */
3659 HeapFree( GetProcessHeap(), 0, lpGList );
3661 /* Should send a DELETEGROUPFROMGROUP message */
3662 FIXME( "message not sent\n" );
3664 return DP_OK;
3667 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3668 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3670 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3671 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3674 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3675 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3677 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3678 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3681 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3682 LPDWORD lpdwBufSize )
3684 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3685 HRESULT hr;
3687 dpCompoundAddress.dwDataSize = sizeof( GUID );
3688 dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3689 dpCompoundAddress.lpData = lpcSpGuid;
3691 *lplpAddrBuf = NULL;
3692 *lpdwBufSize = 0;
3694 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3695 lpdwBufSize, TRUE );
3697 if( hr != DPERR_BUFFERTOOSMALL )
3699 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3700 return FALSE;
3703 /* Now allocate the buffer */
3704 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3705 *lpdwBufSize );
3707 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3708 lpdwBufSize, TRUE );
3709 if( FAILED(hr) )
3711 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3712 return FALSE;
3715 return TRUE;
3718 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
3719 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3721 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3722 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3724 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3725 if( dwFlags == 0 )
3727 dwFlags = DPCONNECTION_DIRECTPLAY;
3730 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3731 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3734 return DPERR_INVALIDFLAGS;
3737 if( !lpEnumCallback )
3739 return DPERR_INVALIDPARAMS;
3742 /* Enumerate DirectPlay service providers */
3743 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3745 HKEY hkResult;
3746 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3747 LPCSTR guidDataSubKey = "Guid";
3748 char subKeyName[51];
3749 DWORD dwIndex, sizeOfSubKeyName=50;
3750 FILETIME filetime;
3752 /* Need to loop over the service providers in the registry */
3753 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3754 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3756 /* Hmmm. Does this mean that there are no service providers? */
3757 ERR(": no service providers?\n");
3758 return DP_OK;
3762 /* Traverse all the service providers we have available */
3763 for( dwIndex=0;
3764 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3765 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3766 ++dwIndex, sizeOfSubKeyName=51 )
3769 HKEY hkServiceProvider;
3770 GUID serviceProviderGUID;
3771 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3772 char returnBuffer[51];
3773 WCHAR buff[51];
3774 DPNAME dpName;
3775 BOOL bBuildPass;
3777 LPVOID lpAddressBuffer = NULL;
3778 DWORD dwAddressBufferSize = 0;
3780 TRACE(" this time through: %s\n", subKeyName );
3782 /* Get a handle for this particular service provider */
3783 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3784 &hkServiceProvider ) != ERROR_SUCCESS )
3786 ERR(": what the heck is going on?\n" );
3787 continue;
3790 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3791 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3792 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3794 ERR(": missing GUID registry data members\n" );
3795 RegCloseKey(hkServiceProvider);
3796 continue;
3798 RegCloseKey(hkServiceProvider);
3800 /* FIXME: Check return types to ensure we're interpreting data right */
3801 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3802 CLSIDFromString( buff, &serviceProviderGUID );
3803 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3805 /* Fill in the DPNAME struct for the service provider */
3806 dpName.dwSize = sizeof( dpName );
3807 dpName.dwFlags = 0;
3808 dpName.u1.lpszShortNameA = subKeyName;
3809 dpName.u2.lpszLongNameA = NULL;
3811 /* Create the compound address for the service provider.
3812 * NOTE: This is a gruesome architectural scar right now. DP
3813 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3814 * native dll just gets around this little bit by allocating an
3815 * 80 byte buffer which isn't even filled with a valid compound
3816 * address. Oh well. Creating a proper compound address is the
3817 * way to go anyways despite this method taking slightly more
3818 * heap space and realtime :) */
3820 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3821 &lpAddressBuffer,
3822 &dwAddressBufferSize );
3823 if( !bBuildPass )
3825 ERR( "Can't build compound addr\n" );
3826 return DPERR_GENERIC;
3829 /* The enumeration will return FALSE if we are not to continue */
3830 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3831 &dpName, dwFlags, lpContext ) )
3833 return DP_OK;
3838 /* Enumerate DirectPlayLobby service providers */
3839 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3841 HKEY hkResult;
3842 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3843 LPCSTR guidDataSubKey = "Guid";
3844 char subKeyName[51];
3845 DWORD dwIndex, sizeOfSubKeyName=50;
3846 FILETIME filetime;
3848 /* Need to loop over the service providers in the registry */
3849 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3850 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3852 /* Hmmm. Does this mean that there are no service providers? */
3853 ERR(": no service providers?\n");
3854 return DP_OK;
3858 /* Traverse all the lobby providers we have available */
3859 for( dwIndex=0;
3860 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3861 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3862 ++dwIndex, sizeOfSubKeyName=51 )
3865 HKEY hkServiceProvider;
3866 GUID serviceProviderGUID;
3867 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3868 char returnBuffer[51];
3869 WCHAR buff[51];
3870 DPNAME dpName;
3871 HRESULT hr;
3873 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3874 LPVOID lpAddressBuffer = NULL;
3875 DWORD dwAddressBufferSize = 0;
3877 TRACE(" this time through: %s\n", subKeyName );
3879 /* Get a handle for this particular service provider */
3880 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3881 &hkServiceProvider ) != ERROR_SUCCESS )
3883 ERR(": what the heck is going on?\n" );
3884 continue;
3887 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3888 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3889 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3891 ERR(": missing GUID registry data members\n" );
3892 RegCloseKey(hkServiceProvider);
3893 continue;
3895 RegCloseKey(hkServiceProvider);
3897 /* FIXME: Check return types to ensure we're interpreting data right */
3898 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3899 CLSIDFromString( buff, &serviceProviderGUID );
3900 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3902 /* Fill in the DPNAME struct for the service provider */
3903 dpName.dwSize = sizeof( dpName );
3904 dpName.dwFlags = 0;
3905 dpName.u1.lpszShortNameA = subKeyName;
3906 dpName.u2.lpszLongNameA = NULL;
3908 /* Create the compound address for the service provider.
3909 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3910 nast stuff. This may be why the native dll just gets around this little bit by
3911 allocating an 80 byte buffer which isn't even a filled with a valid compound
3912 address. Oh well. Creating a proper compound address is the way to go anyways
3913 despite this method taking slightly more heap space and realtime :) */
3915 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3916 dpCompoundAddress.dwDataSize = sizeof( GUID );
3917 dpCompoundAddress.lpData = &serviceProviderGUID;
3919 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3920 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3922 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3923 return hr;
3926 /* Now allocate the buffer */
3927 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3929 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3930 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3932 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3933 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3934 return hr;
3937 /* The enumeration will return FALSE if we are not to continue */
3938 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3939 &dpName, dwFlags, lpContext ) )
3941 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3942 return DP_OK;
3944 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3948 return DP_OK;
3951 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3952 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3954 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3955 FIXME("(%p)->(%p,%p,%p,0x%08x): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3956 return DP_OK;
3959 static HRESULT DP_IF_EnumGroupsInGroup
3960 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3961 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3962 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3964 lpGroupList lpGList;
3965 lpGroupData lpGData;
3967 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
3968 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3969 lpContext, dwFlags, bAnsi );
3971 if( This->dp2->connectionInitialized == NO_PROVIDER )
3973 return DPERR_UNINITIALIZED;
3976 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3978 return DPERR_INVALIDGROUP;
3981 if( DPQ_IS_EMPTY( lpGData->groups ) )
3983 return DP_OK;
3986 lpGList = DPQ_FIRST( lpGData->groups );
3988 for( ;; )
3990 /* FIXME: Should check dwFlags for match here */
3992 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3993 &lpGList->lpGData->name, dwFlags,
3994 lpContext ) )
3996 return DP_OK; /* User requested break */
3999 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
4001 break;
4004 lpGList = DPQ_NEXT( lpGList->groups );
4008 return DP_OK;
4011 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
4012 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
4013 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
4014 DWORD dwFlags )
4016 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4017 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
4018 lpEnumPlayersCallback2, lpContext, dwFlags,
4019 TRUE );
4022 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
4023 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
4024 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
4025 DWORD dwFlags )
4027 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4028 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
4029 lpEnumPlayersCallback2, lpContext, dwFlags,
4030 FALSE );
4033 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
4034 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4036 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4037 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4038 return DP_OK;
4041 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
4042 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4044 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4045 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4046 return DP_OK;
4049 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
4050 REFGUID guidDataType,
4051 DWORD dwDataSize,
4052 LPCVOID lpData,
4053 LPVOID lpContext )
4055 /* Looking for the GUID of the provider to load */
4056 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
4057 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
4060 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4061 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
4063 if( dwDataSize != sizeof( GUID ) )
4065 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4068 memcpy( lpContext, lpData, dwDataSize );
4070 /* There shouldn't be more than 1 GUID/compound address */
4071 return FALSE;
4074 /* Still waiting for what we want */
4075 return TRUE;
4079 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4080 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4082 UINT i;
4083 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4084 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4085 LPCSTR guidDataSubKey = "Guid";
4086 LPCSTR majVerDataSubKey = "dwReserved1";
4087 LPCSTR minVerDataSubKey = "dwReserved2";
4088 LPCSTR pathSubKey = "Path";
4090 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4092 /* FIXME: Cloned code with a quick hack. */
4093 for( i=0; i<2; i++ )
4095 HKEY hkResult;
4096 LPCSTR searchSubKey;
4097 char subKeyName[51];
4098 DWORD dwIndex, sizeOfSubKeyName=50;
4099 FILETIME filetime;
4101 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4102 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4105 /* Need to loop over the service providers in the registry */
4106 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4107 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4109 /* Hmmm. Does this mean that there are no service providers? */
4110 ERR(": no service providers?\n");
4111 return 0;
4114 /* Traverse all the service providers we have available */
4115 for( dwIndex=0;
4116 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4117 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4118 ++dwIndex, sizeOfSubKeyName=51 )
4121 HKEY hkServiceProvider;
4122 GUID serviceProviderGUID;
4123 DWORD returnType, sizeOfReturnBuffer = 255;
4124 char returnBuffer[256];
4125 WCHAR buff[51];
4126 DWORD dwTemp, len;
4128 TRACE(" this time through: %s\n", subKeyName );
4130 /* Get a handle for this particular service provider */
4131 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4132 &hkServiceProvider ) != ERROR_SUCCESS )
4134 ERR(": what the heck is going on?\n" );
4135 continue;
4138 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4139 NULL, &returnType, (LPBYTE)returnBuffer,
4140 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4142 ERR(": missing GUID registry data members\n" );
4143 continue;
4146 /* FIXME: Check return types to ensure we're interpreting data right */
4147 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4148 CLSIDFromString( buff, &serviceProviderGUID );
4149 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4151 /* Determine if this is the Service Provider that the user asked for */
4152 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4154 continue;
4157 if( i == 0 ) /* DP SP */
4159 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4160 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4161 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4164 sizeOfReturnBuffer = 255;
4166 /* Get dwReserved1 */
4167 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4168 NULL, &returnType, (LPBYTE)returnBuffer,
4169 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4171 ERR(": missing dwReserved1 registry data members\n") ;
4172 continue;
4175 if( i == 0 )
4176 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4178 sizeOfReturnBuffer = 255;
4180 /* Get dwReserved2 */
4181 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4182 NULL, &returnType, (LPBYTE)returnBuffer,
4183 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4185 ERR(": missing dwReserved1 registry data members\n") ;
4186 continue;
4189 if( i == 0 )
4190 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4192 sizeOfReturnBuffer = 255;
4194 /* Get the path for this service provider */
4195 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4196 NULL, NULL, (LPBYTE)returnBuffer,
4197 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4199 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4200 continue;
4203 TRACE( "Loading %s\n", returnBuffer );
4204 return LoadLibraryA( returnBuffer );
4208 return 0;
4211 static
4212 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4214 HRESULT hr;
4215 LPDPSP_SPINIT SPInit;
4217 /* Initialize the service provider by calling SPInit */
4218 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4220 if( SPInit == NULL )
4222 ERR( "Service provider doesn't provide SPInit interface?\n" );
4223 FreeLibrary( hServiceProvider );
4224 return DPERR_UNAVAILABLE;
4227 TRACE( "Calling SPInit (DP SP entry point)\n" );
4229 hr = (*SPInit)( &This->dp2->spData );
4231 if( FAILED(hr) )
4233 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4234 FreeLibrary( hServiceProvider );
4235 return hr;
4238 /* FIXME: Need to verify the sanity of the returned callback table
4239 * using IsBadCodePtr */
4240 This->dp2->bSPInitialized = TRUE;
4242 /* This interface is now initialized as a DP object */
4243 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4245 /* Store the handle of the module so that we can unload it later */
4246 This->dp2->hServiceProvider = hServiceProvider;
4248 return hr;
4251 static
4252 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4254 HRESULT hr;
4255 LPSP_INIT DPLSPInit;
4257 /* Initialize the service provider by calling SPInit */
4258 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4260 if( DPLSPInit == NULL )
4262 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4263 FreeLibrary( hLobbyProvider );
4264 return DPERR_UNAVAILABLE;
4267 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4269 hr = (*DPLSPInit)( &This->dp2->dplspData );
4271 if( FAILED(hr) )
4273 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4274 FreeLibrary( hLobbyProvider );
4275 return hr;
4278 /* FIXME: Need to verify the sanity of the returned callback table
4279 * using IsBadCodePtr */
4281 This->dp2->bDPLSPInitialized = TRUE;
4283 /* This interface is now initialized as a lobby object */
4284 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4286 /* Store the handle of the module so that we can unload it later */
4287 This->dp2->hDPLobbyProvider = hLobbyProvider;
4289 return hr;
4292 static HRESULT DP_IF_InitializeConnection
4293 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4295 HMODULE hServiceProvider;
4296 HRESULT hr;
4297 GUID guidSP;
4298 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4299 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4301 TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4303 if ( lpConnection == NULL )
4305 return DPERR_INVALIDPARAMS;
4308 if( dwFlags != 0 )
4310 return DPERR_INVALIDFLAGS;
4313 if( This->dp2->connectionInitialized != NO_PROVIDER )
4315 return DPERR_ALREADYINITIALIZED;
4318 /* Find out what the requested SP is and how large this buffer is */
4319 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4320 dwAddrSize, &guidSP );
4322 if( FAILED(hr) )
4324 ERR( "Invalid compound address?\n" );
4325 return DPERR_UNAVAILABLE;
4328 /* Load the service provider */
4329 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4331 if( hServiceProvider == 0 )
4333 ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4334 return DPERR_UNAVAILABLE;
4337 if( bIsDpSp )
4339 /* Fill in what we can of the Service Provider required information.
4340 * The rest was be done in DP_LoadSP
4342 This->dp2->spData.lpAddress = lpConnection;
4343 This->dp2->spData.dwAddressSize = dwAddrSize;
4344 This->dp2->spData.lpGuid = &guidSP;
4346 hr = DP_InitializeDPSP( This, hServiceProvider );
4348 else
4350 This->dp2->dplspData.lpAddress = lpConnection;
4352 hr = DP_InitializeDPLSP( This, hServiceProvider );
4355 if( FAILED(hr) )
4357 return hr;
4360 return DP_OK;
4363 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4364 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4366 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4368 /* This may not be externally invoked once either an SP or LP is initialized */
4369 if( This->dp2->connectionInitialized != NO_PROVIDER )
4371 return DPERR_ALREADYINITIALIZED;
4374 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4377 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4378 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4380 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4382 /* This may not be externally invoked once either an SP or LP is initialized */
4383 if( This->dp2->connectionInitialized != NO_PROVIDER )
4385 return DPERR_ALREADYINITIALIZED;
4388 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4391 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4392 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4393 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4395 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4396 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4399 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4400 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4401 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4403 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4404 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4407 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4408 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4410 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4411 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4412 return DP_OK;
4415 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4416 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4418 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4419 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4420 return DP_OK;
4423 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4424 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4426 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4427 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4428 return DP_OK;
4431 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4432 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4434 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4435 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4436 return DP_OK;
4439 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4440 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4442 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4443 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4444 return DP_OK;
4447 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4448 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4450 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4451 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4452 return DP_OK;
4455 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4456 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4458 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4459 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4460 return DP_OK;
4463 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4464 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4466 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4467 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4468 return DP_OK;
4471 static HRESULT DP_IF_GetGroupParent
4472 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4473 BOOL bAnsi )
4475 lpGroupData lpGData;
4477 TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4479 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4481 return DPERR_INVALIDGROUP;
4484 *lpidGroup = lpGData->dpid;
4486 return DP_OK;
4489 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4490 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4492 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4493 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4495 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4496 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4498 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4499 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4502 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4503 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4505 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4506 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4507 return DP_OK;
4510 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4511 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4513 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4514 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4515 return DP_OK;
4518 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4519 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4521 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4522 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4523 return DP_OK;
4526 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4527 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4529 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4530 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4531 return DP_OK;
4534 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4535 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4537 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4538 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4539 return DP_OK;
4542 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4543 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4545 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4546 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4547 return DP_OK;
4550 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4551 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4553 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4554 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4555 return DP_OK;
4558 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4559 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4561 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4562 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4563 return DP_OK;
4566 static HRESULT DP_SendEx
4567 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4568 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4569 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4571 BOOL bValidDestination = FALSE;
4573 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4574 ": stub\n",
4575 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4576 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4578 if( This->dp2->connectionInitialized == NO_PROVIDER )
4580 return DPERR_UNINITIALIZED;
4583 /* FIXME: Add parameter checking */
4584 /* FIXME: First call to this needs to acquire a message id which will be
4585 * used for multiple sends
4588 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4590 /* Verify that the message is being sent from a valid local player. The
4591 * from player may be anonymous DPID_UNKNOWN
4593 if( idFrom != DPID_UNKNOWN )
4595 if( DP_FindPlayer( This, idFrom ) == NULL )
4597 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4598 return DPERR_INVALIDPLAYER;
4602 /* Verify that the message is being sent to a valid player, group or to
4603 * everyone. If it's valid, send it to those players.
4605 if( idTo == DPID_ALLPLAYERS )
4607 bValidDestination = TRUE;
4609 /* See if SP has the ability to multicast. If so, use it */
4610 if( This->dp2->spData.lpCB->SendToGroupEx )
4612 FIXME( "Use group sendex to group 0\n" );
4614 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4616 FIXME( "Use obsolete group send to group 0\n" );
4618 else /* No multicast, multiplicate */
4620 /* Send to all players we know about */
4621 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4625 if( ( !bValidDestination ) &&
4626 ( DP_FindPlayer( This, idTo ) != NULL )
4629 bValidDestination = TRUE;
4631 /* Have the service provider send this message */
4632 /* FIXME: Could optimize for local interface sends */
4633 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4634 dwTimeout, lpContext, lpdwMsgID );
4637 if( ( !bValidDestination ) &&
4638 ( DP_FindAnyGroup( This, idTo ) != NULL )
4641 bValidDestination = TRUE;
4643 /* See if SP has the ability to multicast. If so, use it */
4644 if( This->dp2->spData.lpCB->SendToGroupEx )
4646 FIXME( "Use group sendex\n" );
4648 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4650 FIXME( "Use obsolete group send to group\n" );
4652 else /* No multicast, multiplicate */
4654 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4657 #if 0
4658 if( bExpectReply )
4660 DWORD dwWaitReturn;
4662 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4664 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4665 if( dwWaitReturn != WAIT_OBJECT_0 )
4667 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4670 #endif
4673 if( !bValidDestination )
4675 return DPERR_INVALIDPLAYER;
4677 else
4679 /* FIXME: Should return what the send returned */
4680 return DP_OK;
4685 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4686 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4687 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4688 LPVOID lpContext, LPDWORD lpdwMsgID )
4690 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4691 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4692 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4695 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4696 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4697 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4698 LPVOID lpContext, LPDWORD lpdwMsgID )
4700 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4701 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4702 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4705 static HRESULT DP_SP_SendEx
4706 ( IDirectPlay2Impl* This, DWORD dwFlags,
4707 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4708 LPVOID lpContext, LPDWORD lpdwMsgID )
4710 LPDPMSG lpMElem;
4712 FIXME( ": stub\n" );
4714 /* FIXME: This queuing should only be for async messages */
4716 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4717 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4719 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4721 /* FIXME: Need to queue based on priority */
4722 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4724 return DP_OK;
4727 static HRESULT DP_IF_GetMessageQueue
4728 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4729 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4731 HRESULT hr = DP_OK;
4733 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4734 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4736 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4737 /* FIXME: What about sends which are not immediate? */
4739 if( This->dp2->spData.lpCB->GetMessageQueue )
4741 DPSP_GETMESSAGEQUEUEDATA data;
4743 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4745 /* FIXME: None of this is documented :( */
4747 data.lpISP = This->dp2->spData.lpISP;
4748 data.dwFlags = dwFlags;
4749 data.idFrom = idFrom;
4750 data.idTo = idTo;
4751 data.lpdwNumMsgs = lpdwNumMsgs;
4752 data.lpdwNumBytes = lpdwNumBytes;
4754 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4756 else
4758 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4761 return hr;
4764 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4765 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4766 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4768 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4769 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4770 lpdwNumBytes, TRUE );
4773 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4774 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4775 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4777 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4778 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4779 lpdwNumBytes, FALSE );
4782 static HRESULT DP_IF_CancelMessage
4783 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4784 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4786 HRESULT hr = DP_OK;
4788 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4789 This, dwMsgID, dwFlags, bAnsi );
4791 if( This->dp2->spData.lpCB->Cancel )
4793 DPSP_CANCELDATA data;
4795 TRACE( "Calling SP Cancel\n" );
4797 /* FIXME: Undocumented callback */
4799 data.lpISP = This->dp2->spData.lpISP;
4800 data.dwFlags = dwFlags;
4801 data.lprglpvSPMsgID = NULL;
4802 data.cSPMsgID = dwMsgID;
4803 data.dwMinPriority = dwMinPriority;
4804 data.dwMaxPriority = dwMaxPriority;
4806 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4808 else
4810 FIXME( "SP doesn't implement Cancel\n" );
4813 return hr;
4816 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4817 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4819 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4821 if( dwFlags != 0 )
4823 return DPERR_INVALIDFLAGS;
4826 if( dwMsgID == 0 )
4828 dwFlags |= DPCANCELSEND_ALL;
4831 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4834 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4835 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4837 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4839 if( dwFlags != 0 )
4841 return DPERR_INVALIDFLAGS;
4844 if( dwMsgID == 0 )
4846 dwFlags |= DPCANCELSEND_ALL;
4849 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4852 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4853 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4854 DWORD dwFlags )
4856 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4858 if( dwFlags != 0 )
4860 return DPERR_INVALIDFLAGS;
4863 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4864 dwMaxPriority, TRUE );
4867 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4868 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4869 DWORD dwFlags )
4871 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4873 if( dwFlags != 0 )
4875 return DPERR_INVALIDFLAGS;
4878 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4879 dwMaxPriority, FALSE );
4882 /* Note: Hack so we can reuse the old functions without compiler warnings */
4883 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4884 # define XCAST(fun) (typeof(directPlay2WVT.fun))
4885 #else
4886 # define XCAST(fun) (void*)
4887 #endif
4889 static const IDirectPlay2Vtbl directPlay2WVT =
4891 XCAST(QueryInterface)DP_QueryInterface,
4892 XCAST(AddRef)DP_AddRef,
4893 XCAST(Release)DP_Release,
4895 DirectPlay2WImpl_AddPlayerToGroup,
4896 DirectPlay2WImpl_Close,
4897 DirectPlay2WImpl_CreateGroup,
4898 DirectPlay2WImpl_CreatePlayer,
4899 DirectPlay2WImpl_DeletePlayerFromGroup,
4900 DirectPlay2WImpl_DestroyGroup,
4901 DirectPlay2WImpl_DestroyPlayer,
4902 DirectPlay2WImpl_EnumGroupPlayers,
4903 DirectPlay2WImpl_EnumGroups,
4904 DirectPlay2WImpl_EnumPlayers,
4905 DirectPlay2WImpl_EnumSessions,
4906 DirectPlay2WImpl_GetCaps,
4907 DirectPlay2WImpl_GetGroupData,
4908 DirectPlay2WImpl_GetGroupName,
4909 DirectPlay2WImpl_GetMessageCount,
4910 DirectPlay2WImpl_GetPlayerAddress,
4911 DirectPlay2WImpl_GetPlayerCaps,
4912 DirectPlay2WImpl_GetPlayerData,
4913 DirectPlay2WImpl_GetPlayerName,
4914 DirectPlay2WImpl_GetSessionDesc,
4915 DirectPlay2WImpl_Initialize,
4916 DirectPlay2WImpl_Open,
4917 DirectPlay2WImpl_Receive,
4918 DirectPlay2WImpl_Send,
4919 DirectPlay2WImpl_SetGroupData,
4920 DirectPlay2WImpl_SetGroupName,
4921 DirectPlay2WImpl_SetPlayerData,
4922 DirectPlay2WImpl_SetPlayerName,
4923 DirectPlay2WImpl_SetSessionDesc
4925 #undef XCAST
4927 /* Note: Hack so we can reuse the old functions without compiler warnings */
4928 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4929 # define XCAST(fun) (typeof(directPlay2AVT.fun))
4930 #else
4931 # define XCAST(fun) (void*)
4932 #endif
4934 static const IDirectPlay2Vtbl directPlay2AVT =
4936 XCAST(QueryInterface)DP_QueryInterface,
4937 XCAST(AddRef)DP_AddRef,
4938 XCAST(Release)DP_Release,
4940 DirectPlay2AImpl_AddPlayerToGroup,
4941 DirectPlay2AImpl_Close,
4942 DirectPlay2AImpl_CreateGroup,
4943 DirectPlay2AImpl_CreatePlayer,
4944 DirectPlay2AImpl_DeletePlayerFromGroup,
4945 DirectPlay2AImpl_DestroyGroup,
4946 DirectPlay2AImpl_DestroyPlayer,
4947 DirectPlay2AImpl_EnumGroupPlayers,
4948 DirectPlay2AImpl_EnumGroups,
4949 DirectPlay2AImpl_EnumPlayers,
4950 DirectPlay2AImpl_EnumSessions,
4951 DirectPlay2AImpl_GetCaps,
4952 DirectPlay2AImpl_GetGroupData,
4953 DirectPlay2AImpl_GetGroupName,
4954 DirectPlay2AImpl_GetMessageCount,
4955 DirectPlay2AImpl_GetPlayerAddress,
4956 DirectPlay2AImpl_GetPlayerCaps,
4957 DirectPlay2AImpl_GetPlayerData,
4958 DirectPlay2AImpl_GetPlayerName,
4959 DirectPlay2AImpl_GetSessionDesc,
4960 DirectPlay2AImpl_Initialize,
4961 DirectPlay2AImpl_Open,
4962 DirectPlay2AImpl_Receive,
4963 DirectPlay2AImpl_Send,
4964 DirectPlay2AImpl_SetGroupData,
4965 DirectPlay2AImpl_SetGroupName,
4966 DirectPlay2AImpl_SetPlayerData,
4967 DirectPlay2AImpl_SetPlayerName,
4968 DirectPlay2AImpl_SetSessionDesc
4970 #undef XCAST
4973 /* Note: Hack so we can reuse the old functions without compiler warnings */
4974 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4975 # define XCAST(fun) (typeof(directPlay3AVT.fun))
4976 #else
4977 # define XCAST(fun) (void*)
4978 #endif
4980 static const IDirectPlay3Vtbl directPlay3AVT =
4982 XCAST(QueryInterface)DP_QueryInterface,
4983 XCAST(AddRef)DP_AddRef,
4984 XCAST(Release)DP_Release,
4986 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
4987 XCAST(Close)DirectPlay2AImpl_Close,
4988 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
4989 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
4990 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
4991 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
4992 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
4993 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
4994 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
4995 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
4996 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
4997 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
4998 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
4999 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5000 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5001 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5002 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5003 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5004 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5005 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5006 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5007 XCAST(Open)DirectPlay2AImpl_Open,
5008 XCAST(Receive)DirectPlay2AImpl_Receive,
5009 XCAST(Send)DirectPlay2AImpl_Send,
5010 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5011 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5012 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5013 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5014 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5016 DirectPlay3AImpl_AddGroupToGroup,
5017 DirectPlay3AImpl_CreateGroupInGroup,
5018 DirectPlay3AImpl_DeleteGroupFromGroup,
5019 DirectPlay3AImpl_EnumConnections,
5020 DirectPlay3AImpl_EnumGroupsInGroup,
5021 DirectPlay3AImpl_GetGroupConnectionSettings,
5022 DirectPlay3AImpl_InitializeConnection,
5023 DirectPlay3AImpl_SecureOpen,
5024 DirectPlay3AImpl_SendChatMessage,
5025 DirectPlay3AImpl_SetGroupConnectionSettings,
5026 DirectPlay3AImpl_StartSession,
5027 DirectPlay3AImpl_GetGroupFlags,
5028 DirectPlay3AImpl_GetGroupParent,
5029 DirectPlay3AImpl_GetPlayerAccount,
5030 DirectPlay3AImpl_GetPlayerFlags
5032 #undef XCAST
5034 /* Note: Hack so we can reuse the old functions without compiler warnings */
5035 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5036 # define XCAST(fun) (typeof(directPlay3WVT.fun))
5037 #else
5038 # define XCAST(fun) (void*)
5039 #endif
5040 static const IDirectPlay3Vtbl directPlay3WVT =
5042 XCAST(QueryInterface)DP_QueryInterface,
5043 XCAST(AddRef)DP_AddRef,
5044 XCAST(Release)DP_Release,
5046 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5047 XCAST(Close)DirectPlay2WImpl_Close,
5048 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5049 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5050 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5051 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5052 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5053 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5054 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5055 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5056 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5057 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5058 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5059 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5060 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5061 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5062 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5063 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5064 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5065 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5066 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5067 XCAST(Open)DirectPlay2WImpl_Open,
5068 XCAST(Receive)DirectPlay2WImpl_Receive,
5069 XCAST(Send)DirectPlay2WImpl_Send,
5070 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5071 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5072 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5073 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5074 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5076 DirectPlay3WImpl_AddGroupToGroup,
5077 DirectPlay3WImpl_CreateGroupInGroup,
5078 DirectPlay3WImpl_DeleteGroupFromGroup,
5079 DirectPlay3WImpl_EnumConnections,
5080 DirectPlay3WImpl_EnumGroupsInGroup,
5081 DirectPlay3WImpl_GetGroupConnectionSettings,
5082 DirectPlay3WImpl_InitializeConnection,
5083 DirectPlay3WImpl_SecureOpen,
5084 DirectPlay3WImpl_SendChatMessage,
5085 DirectPlay3WImpl_SetGroupConnectionSettings,
5086 DirectPlay3WImpl_StartSession,
5087 DirectPlay3WImpl_GetGroupFlags,
5088 DirectPlay3WImpl_GetGroupParent,
5089 DirectPlay3WImpl_GetPlayerAccount,
5090 DirectPlay3WImpl_GetPlayerFlags
5092 #undef XCAST
5094 /* Note: Hack so we can reuse the old functions without compiler warnings */
5095 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5096 # define XCAST(fun) (typeof(directPlay4WVT.fun))
5097 #else
5098 # define XCAST(fun) (void*)
5099 #endif
5100 static const IDirectPlay4Vtbl directPlay4WVT =
5102 XCAST(QueryInterface)DP_QueryInterface,
5103 XCAST(AddRef)DP_AddRef,
5104 XCAST(Release)DP_Release,
5106 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5107 XCAST(Close)DirectPlay2WImpl_Close,
5108 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5109 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5110 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5111 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5112 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5113 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5114 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5115 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5116 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5117 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5118 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5119 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5120 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5121 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5122 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5123 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5124 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5125 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5126 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5127 XCAST(Open)DirectPlay2WImpl_Open,
5128 XCAST(Receive)DirectPlay2WImpl_Receive,
5129 XCAST(Send)DirectPlay2WImpl_Send,
5130 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5131 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5132 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5133 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5134 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5136 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5137 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5138 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5139 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5140 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5141 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5142 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5143 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5144 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5145 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5146 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5147 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5148 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5149 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5150 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5152 DirectPlay4WImpl_GetGroupOwner,
5153 DirectPlay4WImpl_SetGroupOwner,
5154 DirectPlay4WImpl_SendEx,
5155 DirectPlay4WImpl_GetMessageQueue,
5156 DirectPlay4WImpl_CancelMessage,
5157 DirectPlay4WImpl_CancelPriority
5159 #undef XCAST
5162 /* Note: Hack so we can reuse the old functions without compiler warnings */
5163 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5164 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5165 #else
5166 # define XCAST(fun) (void*)
5167 #endif
5168 static const IDirectPlay4Vtbl directPlay4AVT =
5170 XCAST(QueryInterface)DP_QueryInterface,
5171 XCAST(AddRef)DP_AddRef,
5172 XCAST(Release)DP_Release,
5174 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5175 XCAST(Close)DirectPlay2AImpl_Close,
5176 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5177 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5178 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5179 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5180 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5181 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5182 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5183 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5184 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5185 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5186 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5187 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5188 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5189 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5190 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5191 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5192 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5193 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5194 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5195 XCAST(Open)DirectPlay2AImpl_Open,
5196 XCAST(Receive)DirectPlay2AImpl_Receive,
5197 XCAST(Send)DirectPlay2AImpl_Send,
5198 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5199 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5200 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5201 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5202 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5204 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5205 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5206 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5207 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5208 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5209 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5210 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5211 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5212 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5213 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5214 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5215 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5216 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5217 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5218 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5220 DirectPlay4AImpl_GetGroupOwner,
5221 DirectPlay4AImpl_SetGroupOwner,
5222 DirectPlay4AImpl_SendEx,
5223 DirectPlay4AImpl_GetMessageQueue,
5224 DirectPlay4AImpl_CancelMessage,
5225 DirectPlay4AImpl_CancelPriority
5227 #undef XCAST
5229 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5230 DPID idPlayer,
5231 LPVOID* lplpData )
5233 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5235 if( lpPlayer == NULL )
5237 return DPERR_INVALIDPLAYER;
5240 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5242 return DP_OK;
5245 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5246 DPID idPlayer,
5247 LPVOID lpData )
5249 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5251 if( lpPlayer == NULL )
5253 return DPERR_INVALIDPLAYER;
5256 lpPlayer->lpPData->lpSPPlayerData = lpData;
5258 return DP_OK;
5261 /***************************************************************************
5262 * DirectPlayEnumerateAW
5264 * The pointer to the structure lpContext will be filled with the
5265 * appropriate data for each service offered by the OS. These services are
5266 * not necessarily available on this particular machine but are defined
5267 * as simple service providers under the "Service Providers" registry key.
5268 * This structure is then passed to lpEnumCallback for each of the different
5269 * services.
5271 * This API is useful only for applications written using DirectX3 or
5272 * worse. It is superseded by IDirectPlay3::EnumConnections which also
5273 * gives information on the actual connections.
5275 * defn of a service provider:
5276 * A dynamic-link library used by DirectPlay to communicate over a network.
5277 * The service provider contains all the network-specific code required
5278 * to send and receive messages. Online services and network operators can
5279 * supply service providers to use specialized hardware, protocols, communications
5280 * media, and network resources.
5283 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5284 LPDPENUMDPCALLBACKW lpEnumCallbackW,
5285 LPVOID lpContext)
5287 HKEY hkResult;
5288 static const WCHAR searchSubKey[] = {
5289 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5290 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5291 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5292 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5293 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5294 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5296 DWORD dwIndex;
5297 FILETIME filetime;
5299 char *descriptionA = NULL;
5300 DWORD max_sizeOfDescriptionA = 0;
5301 WCHAR *descriptionW = NULL;
5302 DWORD max_sizeOfDescriptionW = 0;
5304 if (!lpEnumCallbackA && !lpEnumCallbackW)
5306 return DPERR_INVALIDPARAMS;
5309 /* Need to loop over the service providers in the registry */
5310 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5311 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5313 /* Hmmm. Does this mean that there are no service providers? */
5314 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5315 return DPERR_GENERIC;
5318 /* Traverse all the service providers we have available */
5319 dwIndex = 0;
5320 while (1)
5322 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5323 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5324 HKEY hkServiceProvider;
5325 GUID serviceProviderGUID;
5326 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5327 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5328 LONG ret_value;
5330 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5331 NULL, NULL, NULL, &filetime);
5332 if (ret_value == ERROR_NO_MORE_ITEMS)
5333 break;
5334 else if (ret_value != ERROR_SUCCESS)
5336 ERR(": could not enumerate on service provider key.\n");
5337 return DPERR_EXCEPTION;
5339 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5341 /* Open the key for this service provider */
5342 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5344 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5345 continue;
5348 /* Get the GUID from the registry */
5349 if (RegQueryValueExW(hkServiceProvider, guidKey,
5350 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5352 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5353 continue;
5355 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5357 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5358 continue;
5360 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5362 /* The enumeration will return FALSE if we are not to continue.
5364 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5365 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5366 * I think that it simply means that they are in-line with DirectX 6.0
5368 if (lpEnumCallbackA)
5370 DWORD sizeOfDescription = 0;
5372 /* Note that this is the A case of this function, so use the A variant to get the description string */
5373 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5374 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5376 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5377 continue;
5379 if (sizeOfDescription > max_sizeOfDescriptionA)
5381 HeapFree(GetProcessHeap(), 0, descriptionA);
5382 max_sizeOfDescriptionA = sizeOfDescription;
5384 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5385 RegQueryValueExA(hkServiceProvider, "DescriptionA",
5386 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5388 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5389 goto end;
5391 else
5393 DWORD sizeOfDescription = 0;
5395 if (RegQueryValueExW(hkServiceProvider, descW,
5396 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5398 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5399 continue;
5401 if (sizeOfDescription > max_sizeOfDescriptionW)
5403 HeapFree(GetProcessHeap(), 0, descriptionW);
5404 max_sizeOfDescriptionW = sizeOfDescription;
5406 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5407 RegQueryValueExW(hkServiceProvider, descW,
5408 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5410 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5411 goto end;
5414 dwIndex++;
5417 end:
5418 HeapFree(GetProcessHeap(), 0, descriptionA);
5419 HeapFree(GetProcessHeap(), 0, descriptionW);
5421 return DP_OK;
5424 /***************************************************************************
5425 * DirectPlayEnumerate [DPLAYX.9]
5426 * DirectPlayEnumerateA [DPLAYX.2]
5428 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5430 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5432 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5435 /***************************************************************************
5436 * DirectPlayEnumerateW [DPLAYX.3]
5438 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5440 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5442 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5445 typedef struct tagCreateEnum
5447 LPVOID lpConn;
5448 LPCGUID lpGuid;
5449 } CreateEnumData, *lpCreateEnumData;
5451 /* Find and copy the matching connection for the SP guid */
5452 static BOOL CALLBACK cbDPCreateEnumConnections(
5453 LPCGUID lpguidSP,
5454 LPVOID lpConnection,
5455 DWORD dwConnectionSize,
5456 LPCDPNAME lpName,
5457 DWORD dwFlags,
5458 LPVOID lpContext)
5460 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5462 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5464 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5466 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5467 dwConnectionSize );
5468 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5470 /* Found the record that we were looking for */
5471 return FALSE;
5474 /* Haven't found what were looking for yet */
5475 return TRUE;
5479 /***************************************************************************
5480 * DirectPlayCreate [DPLAYX.1]
5483 HRESULT WINAPI DirectPlayCreate
5484 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5486 HRESULT hr;
5487 LPDIRECTPLAY3A lpDP3A;
5488 CreateEnumData cbData;
5490 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5492 if( pUnk != NULL )
5494 return CLASS_E_NOAGGREGATION;
5497 if( (lplpDP == NULL) || (lpGUID == NULL) )
5499 return DPERR_INVALIDPARAMS;
5503 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5504 give them an IDirectPlay2A object and hope that doesn't cause problems */
5505 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5507 return DPERR_UNAVAILABLE;
5510 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5512 /* The GUID_NULL means don't bind a service provider. Just return the
5513 interface as is */
5514 return DP_OK;
5517 /* Bind the desired service provider since lpGUID is non NULL */
5518 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5520 /* We're going to use a DP3 interface */
5521 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5522 (LPVOID*)&lpDP3A );
5523 if( FAILED(hr) )
5525 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5526 return hr;
5529 cbData.lpConn = NULL;
5530 cbData.lpGuid = lpGUID;
5532 /* We were given a service provider, find info about it... */
5533 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5534 &cbData, DPCONNECTION_DIRECTPLAY );
5535 if( ( FAILED(hr) ) ||
5536 ( cbData.lpConn == NULL )
5539 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5540 IDirectPlayX_Release( lpDP3A );
5541 return DPERR_UNAVAILABLE;
5544 /* Initialize the service provider */
5545 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5546 if( FAILED(hr) )
5548 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5549 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5550 IDirectPlayX_Release( lpDP3A );
5551 return hr;
5554 /* Release our version of the interface now that we're done with it */
5555 IDirectPlayX_Release( lpDP3A );
5556 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5558 return DP_OK;