Automatically detect whether the entry point is main or WinMain
[wine/multimedia.git] / dlls / dplayx / dplay.c
bloba99ea62eeb53294ecdae9f6f91537bdba16d6dbb
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "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, LPDPNAME lpSrc, BOOL bAnsi );
58 static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
59 LPVOID lpData, DWORD dwDataSize );
61 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, LPDPID lpid,
62 LPDPNAME 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 /* Helper methods for player/group interfaces */
80 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
81 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
82 DPID idPlayer, BOOL bAnsi );
83 static HRESULT WINAPI DP_IF_CreatePlayer
84 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
85 LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
86 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
87 static HRESULT WINAPI DP_IF_DestroyGroup
88 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
89 static HRESULT WINAPI DP_IF_DestroyPlayer
90 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
91 static HRESULT WINAPI DP_IF_EnumGroupPlayers
92 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
93 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
94 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
95 static HRESULT WINAPI DP_IF_EnumGroups
96 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
97 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
98 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
99 static HRESULT WINAPI DP_IF_EnumPlayers
100 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
101 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
102 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
103 static HRESULT WINAPI DP_IF_GetGroupData
104 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
105 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
106 static HRESULT WINAPI DP_IF_GetGroupName
107 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
108 LPDWORD lpdwDataSize, BOOL bAnsi );
109 static HRESULT WINAPI DP_IF_GetPlayerData
110 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
111 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
112 static HRESULT WINAPI DP_IF_GetPlayerName
113 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
114 LPDWORD lpdwDataSize, BOOL bAnsi );
115 static HRESULT WINAPI DP_IF_SetGroupName
116 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
117 DWORD dwFlags, BOOL bAnsi );
118 static HRESULT WINAPI DP_IF_SetPlayerData
119 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
120 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
121 static HRESULT WINAPI DP_IF_SetPlayerName
122 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
123 DWORD dwFlags, BOOL bAnsi );
124 static HRESULT WINAPI DP_IF_AddGroupToGroup
125 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
126 static HRESULT WINAPI DP_IF_CreateGroup
127 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
128 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
129 DWORD dwFlags, BOOL bAnsi );
130 static HRESULT WINAPI DP_IF_CreateGroupInGroup
131 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
132 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
133 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
134 static HRESULT WINAPI DP_IF_AddPlayerToGroup
135 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
136 DPID idPlayer, BOOL bAnsi );
137 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
138 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
139 static HRESULT WINAPI DP_SetSessionDesc
140 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
141 DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
142 static HRESULT WINAPI DP_SecureOpen
143 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
144 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
145 BOOL bAnsi );
146 static HRESULT WINAPI DP_SendEx
147 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
148 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
149 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
150 static HRESULT WINAPI DP_IF_Receive
151 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
152 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
153 static HRESULT WINAPI DP_IF_GetMessageQueue
154 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
155 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
156 static HRESULT WINAPI DP_SP_SendEx
157 ( IDirectPlay2Impl* This, DWORD dwFlags,
158 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
159 LPVOID lpContext, LPDWORD lpdwMsgID );
160 static HRESULT WINAPI DP_IF_SetGroupData
161 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
162 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
163 static HRESULT WINAPI DP_IF_GetPlayerCaps
164 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
165 DWORD dwFlags );
166 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
167 static HRESULT WINAPI DP_IF_CancelMessage
168 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
169 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
170 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
171 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
172 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
173 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
174 static HRESULT WINAPI DP_IF_GetGroupParent
175 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
176 BOOL bAnsi );
177 static HRESULT WINAPI DP_IF_GetCaps
178 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
179 static HRESULT WINAPI DP_IF_EnumSessions
180 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
181 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
182 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
183 static HRESULT WINAPI DP_IF_InitializeConnection
184 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
185 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
186 LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
187 DWORD dwFlags, LPVOID lpContext );
188 static BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
189 LPDWORD lpdwBufSize );
193 static inline DPID DP_NextObjectId(void);
194 static DPID DP_GetRemoteNextObjectId(void);
197 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
198 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
201 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
202 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
203 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
210 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
211 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
212 we don't have to change much */
213 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
215 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
216 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
218 /* Strip out all dwFlags values for CREATEPLAYER msg */
219 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
221 static DWORD kludgePlayerGroupId = 1000;
223 /* ------------------------------------------------------------------ */
226 static BOOL DP_CreateIUnknown( LPVOID lpDP )
228 ICOM_THIS(IDirectPlay2AImpl,lpDP);
230 This->unk = (DirectPlayIUnknownData*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
231 sizeof( *(This->unk) ) );
232 if ( This->unk == NULL )
234 return FALSE;
237 InitializeCriticalSection( &This->unk->DP_lock );
239 return TRUE;
242 static BOOL DP_DestroyIUnknown( LPVOID lpDP )
244 ICOM_THIS(IDirectPlay2AImpl,lpDP);
246 DeleteCriticalSection( &This->unk->DP_lock );
247 HeapFree( GetProcessHeap(), 0, This->unk );
249 return TRUE;
252 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
254 ICOM_THIS(IDirectPlay2AImpl,lpDP);
256 This->dp2 = (DirectPlay2Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
257 sizeof( *(This->dp2) ) );
258 if ( This->dp2 == NULL )
260 return FALSE;
263 This->dp2->bConnectionOpen = FALSE;
265 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
267 This->dp2->bHostInterface = FALSE;
269 DPQ_INIT(This->dp2->receiveMsgs);
270 DPQ_INIT(This->dp2->sendMsgs);
271 DPQ_INIT(This->dp2->replysExpected);
273 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
275 /* FIXME: Memory leak */
276 return FALSE;
279 /* Provide an initial session desc with nothing in it */
280 This->dp2->lpSessionDesc = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(),
281 HEAP_ZERO_MEMORY,
282 sizeof( *This->dp2->lpSessionDesc ) );
283 if( This->dp2->lpSessionDesc == NULL )
285 /* FIXME: Memory leak */
286 return FALSE;
288 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
290 /* We are a emulating a dp 6 implementation */
291 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
293 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
294 sizeof( *This->dp2->spData.lpCB ) );
295 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
296 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
298 /* This is the pointer to the service provider */
299 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
300 (LPVOID*)&This->dp2->spData.lpISP, This ) )
303 /* FIXME: Memory leak */
304 return FALSE;
307 /* Setup lobby provider information */
308 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
309 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
310 sizeof( *This->dp2->dplspData.lpCB ) );
311 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
313 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
314 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
317 /* FIXME: Memory leak */
318 return FALSE;
321 return TRUE;
324 /* Definition of the global function in dplayx_queue.h. #
325 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
326 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
328 HeapFree( GetProcessHeap(), 0, elem );
331 /* Function to delete the list of groups with this interface. Needs to
332 * delete the group and player lists associated with this group as well
333 * as the group data associated with this group. It should not delete
334 * player data as that is shared with the top player list and will be
335 * deleted with that.
337 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList );
338 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList )
340 DPQ_DELETEQ( elem->lpGData->groups, groups,
341 lpGroupList, cbDeleteElemFromHeap );
342 DPQ_DELETEQ( elem->lpGData->players, players,
343 lpPlayerList, cbDeleteElemFromHeap );
344 HeapFree( GetProcessHeap(), 0, elem->lpGData );
345 HeapFree( GetProcessHeap(), 0, elem );
348 /* Function to delete the list of players with this interface. Needs to
349 * delete the player data for all players as well.
351 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList );
352 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList )
354 HeapFree( GetProcessHeap(), 0, elem->lpPData );
355 HeapFree( GetProcessHeap(), 0, elem );
358 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
360 ICOM_THIS(IDirectPlay2AImpl,lpDP);
362 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
364 TerminateThread( This->dp2->hEnumSessionThread, 0 );
365 CloseHandle( This->dp2->hEnumSessionThread );
368 /* Finish with the SP - have it shutdown */
369 if( This->dp2->spData.lpCB->ShutdownEx )
371 DPSP_SHUTDOWNDATA data;
373 TRACE( "Calling SP ShutdownEx\n" );
375 data.lpISP = This->dp2->spData.lpISP;
377 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
379 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
381 TRACE( "Calling obsolete SP Shutdown\n" );
382 (*This->dp2->spData.lpCB->Shutdown)();
385 /* Unload the SP (if it exists) */
386 if( This->dp2->hServiceProvider != 0 )
388 FreeLibrary( This->dp2->hServiceProvider );
391 /* Unload the Lobby Provider (if it exists) */
392 if( This->dp2->hDPLobbyProvider != 0 )
394 FreeLibrary( This->dp2->hDPLobbyProvider );
397 #if 0
398 DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
399 DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem );
400 #endif
402 /* FIXME: Need to delete receive and send msgs queue contents */
404 NS_DeleteSessionCache( This->dp2->lpNameServerData );
406 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
408 IDirectPlaySP_Release( This->dp2->spData.lpISP );
410 /* Delete the contents */
411 HeapFree( GetProcessHeap(), 0, This->dp2 );
413 return TRUE;
416 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
418 ICOM_THIS(IDirectPlay3AImpl,lpDP);
420 This->dp3 = (DirectPlay3Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
421 sizeof( *(This->dp3) ) );
422 if ( This->dp3 == NULL )
424 return FALSE;
427 return TRUE;
430 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
432 ICOM_THIS(IDirectPlay3AImpl,lpDP);
434 /* Delete the contents */
435 HeapFree( GetProcessHeap(), 0, This->dp3 );
437 return TRUE;
440 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
442 ICOM_THIS(IDirectPlay4AImpl,lpDP);
444 This->dp4 = (DirectPlay4Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
445 sizeof( *(This->dp4) ) );
446 if ( This->dp4 == NULL )
448 return FALSE;
451 return TRUE;
454 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
456 ICOM_THIS(IDirectPlay3AImpl,lpDP);
458 /* Delete the contents */
459 HeapFree( GetProcessHeap(), 0, This->dp4 );
461 return TRUE;
465 /* Create a new interface */
466 extern
467 HRESULT DP_CreateInterface
468 ( REFIID riid, LPVOID* ppvObj )
470 TRACE( " for %s\n", debugstr_guid( riid ) );
472 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
473 sizeof( IDirectPlay2Impl ) );
475 if( *ppvObj == NULL )
477 return DPERR_OUTOFMEMORY;
480 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
482 ICOM_THIS(IDirectPlay2Impl,*ppvObj);
483 This->lpVtbl = &directPlay2WVT;
485 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
487 ICOM_THIS(IDirectPlay2AImpl,*ppvObj);
488 This->lpVtbl = &directPlay2AVT;
490 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
492 ICOM_THIS(IDirectPlay3Impl,*ppvObj);
493 This->lpVtbl = &directPlay3WVT;
495 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
497 ICOM_THIS(IDirectPlay3AImpl,*ppvObj);
498 This->lpVtbl = &directPlay3AVT;
500 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
502 ICOM_THIS(IDirectPlay4Impl,*ppvObj);
503 This->lpVtbl = &directPlay4WVT;
505 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
507 ICOM_THIS(IDirectPlay4AImpl,*ppvObj);
508 This->lpVtbl = &directPlay4AVT;
510 else
512 /* Unsupported interface */
513 HeapFree( GetProcessHeap(), 0, *ppvObj );
514 *ppvObj = NULL;
516 return E_NOINTERFACE;
519 /* Initialize it */
520 if ( DP_CreateIUnknown( *ppvObj ) &&
521 DP_CreateDirectPlay2( *ppvObj ) &&
522 DP_CreateDirectPlay3( *ppvObj ) &&
523 DP_CreateDirectPlay4( *ppvObj )
526 IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
528 return S_OK;
531 /* Initialize failed, destroy it */
532 DP_DestroyDirectPlay4( *ppvObj );
533 DP_DestroyDirectPlay3( *ppvObj );
534 DP_DestroyDirectPlay2( *ppvObj );
535 DP_DestroyIUnknown( *ppvObj );
537 HeapFree( GetProcessHeap(), 0, *ppvObj );
539 *ppvObj = NULL;
540 return DPERR_NOMEMORY;
544 /* Direct Play methods */
546 /* Shared between all dplay types */
547 static HRESULT WINAPI DP_QueryInterface
548 ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
550 ICOM_THIS(IDirectPlay2Impl,iface);
551 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
553 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
554 sizeof( *This ) );
556 if( *ppvObj == NULL )
558 return DPERR_OUTOFMEMORY;
561 CopyMemory( *ppvObj, This, sizeof( *This ) );
562 (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
564 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
566 ICOM_THIS(IDirectPlay2Impl,*ppvObj);
567 This->lpVtbl = &directPlay2WVT;
569 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
571 ICOM_THIS(IDirectPlay2AImpl,*ppvObj);
572 This->lpVtbl = &directPlay2AVT;
574 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
576 ICOM_THIS(IDirectPlay3Impl,*ppvObj);
577 This->lpVtbl = &directPlay3WVT;
579 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
581 ICOM_THIS(IDirectPlay3AImpl,*ppvObj);
582 This->lpVtbl = &directPlay3AVT;
584 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
586 ICOM_THIS(IDirectPlay4Impl,*ppvObj);
587 This->lpVtbl = &directPlay4WVT;
589 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
591 ICOM_THIS(IDirectPlay4AImpl,*ppvObj);
592 This->lpVtbl = &directPlay4AVT;
594 else
596 /* Unsupported interface */
597 HeapFree( GetProcessHeap(), 0, *ppvObj );
598 *ppvObj = NULL;
600 return E_NOINTERFACE;
603 IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
605 return S_OK;
608 /* Shared between all dplay types */
609 static ULONG WINAPI DP_AddRef
610 ( LPDIRECTPLAY3 iface )
612 ULONG ulInterfaceRefCount, ulObjRefCount;
613 ICOM_THIS(IDirectPlay3Impl,iface);
615 ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
616 ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
618 TRACE( "ref count incremented to %lu:%lu for %p\n",
619 ulInterfaceRefCount, ulObjRefCount, This );
621 return ulObjRefCount;
624 static ULONG WINAPI DP_Release
625 ( LPDIRECTPLAY3 iface )
627 ULONG ulInterfaceRefCount, ulObjRefCount;
629 ICOM_THIS(IDirectPlay3Impl,iface);
631 ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
632 ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
634 TRACE( "ref count decremented to %lu:%lu for %p\n",
635 ulInterfaceRefCount, ulObjRefCount, This );
637 /* Deallocate if this is the last reference to the object */
638 if( ulObjRefCount == 0 )
640 /* If we're destroying the object, this must be the last ref
641 of the last interface */
642 DP_DestroyDirectPlay4( This );
643 DP_DestroyDirectPlay3( This );
644 DP_DestroyDirectPlay2( This );
645 DP_DestroyIUnknown( This );
648 /* Deallocate the interface */
649 if( ulInterfaceRefCount == 0 )
651 HeapFree( GetProcessHeap(), 0, This );
654 return ulObjRefCount;
657 static inline DPID DP_NextObjectId(void)
659 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
662 /* *lplpReply will be non NULL iff there is something to reply */
663 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
664 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
665 WORD wCommandId, WORD wVersion,
666 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
668 TRACE( "(%p)->(%p,0x%08lx,%p,%u,%u)\n",
669 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
670 wVersion );
672 switch( wCommandId )
674 /* Name server needs to handle this request */
675 case DPMSGCMD_ENUMSESSIONSREQUEST:
677 /* Reply expected */
678 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
680 break;
683 /* Name server needs to handle this request */
684 case DPMSGCMD_ENUMSESSIONSREPLY:
686 /* No reply expected */
687 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
688 This->dp2->spData.dwSPHeaderSize,
689 (LPDPMSG_ENUMSESSIONSREPLY)lpcMessageBody,
690 This->dp2->lpNameServerData );
691 break;
694 case DPMSGCMD_REQUESTNEWPLAYERID:
696 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg =
697 (LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody;
699 LPDPMSG_NEWPLAYERIDREPLY lpReply;
701 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
703 *lplpReply = (LPDPMSG_NEWPLAYERIDREPLY)HeapAlloc( GetProcessHeap(),
704 HEAP_ZERO_MEMORY,
705 *lpdwMsgSize );
707 FIXME( "Ignoring dwFlags 0x%08lx in request msg\n",
708 lpcMsg->dwFlags );
710 /* Setup the reply */
711 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
712 This->dp2->spData.dwSPHeaderSize );
714 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
715 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
716 lpReply->envelope.wVersion = DPMSGVER_DP6;
718 lpReply->dpidNewPlayerId = DP_NextObjectId();
720 TRACE( "Allocating new playerid 0x%08lx from remote request\n",
721 lpReply->dpidNewPlayerId );
723 break;
726 case DPMSGCMD_GETNAMETABLEREPLY:
727 case DPMSGCMD_NEWPLAYERIDREPLY:
730 #if 0
731 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
732 DebugBreak();
733 #endif
734 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
736 break;
739 #if 1
740 case DPMSGCMD_JUSTENVELOPE:
742 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08lx\n", lpcMessageHeader, ((LPDWORD)lpcMessageHeader)[1] );
743 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
744 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
746 #endif
748 case DPMSGCMD_FORWARDADDPLAYER:
750 #if 0
751 DebugBreak();
752 #endif
753 #if 1
754 TRACE( "Sending message to self to get my addr\n" );
755 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
756 #endif
757 break;
760 case DPMSGCMD_FORWARDADDPLAYERNACK:
762 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
763 break;
766 default:
768 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
769 DebugBreak();
770 break;
774 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
776 return DP_OK;
780 static HRESULT WINAPI DP_IF_AddPlayerToGroup
781 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
782 DPID idPlayer, BOOL bAnsi )
784 lpGroupData lpGData;
785 lpPlayerList lpPList;
786 lpPlayerList lpNewPList;
788 TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n",
789 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
791 /* Find the group */
792 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
794 return DPERR_INVALIDGROUP;
797 /* Find the player */
798 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
800 return DPERR_INVALIDPLAYER;
803 /* Create a player list (ie "shortcut" ) */
804 lpNewPList = (lpPlayerList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
805 sizeof( *lpNewPList ) );
806 if( lpNewPList == NULL )
808 return DPERR_CANTADDPLAYER;
811 /* Add the shortcut */
812 lpPList->lpPData->uRef++;
813 lpNewPList->lpPData = lpPList->lpPData;
815 /* Add the player to the list of players for this group */
816 DPQ_INSERT(lpGData->players,lpNewPList,players);
818 /* Let the SP know that we've added a player to the group */
819 if( This->dp2->spData.lpCB->AddPlayerToGroup )
821 DPSP_ADDPLAYERTOGROUPDATA data;
823 TRACE( "Calling SP AddPlayerToGroup\n" );
825 data.idPlayer = idPlayer;
826 data.idGroup = idGroup;
827 data.lpISP = This->dp2->spData.lpISP;
829 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
832 /* Inform all other peers of the addition of player to the group. If there are
833 * no peers keep this event quiet.
834 * Also, if this event was the result of another machine sending it to us,
835 * don't bother rebroadcasting it.
837 if( ( lpMsgHdr == NULL ) &&
838 This->dp2->lpSessionDesc &&
839 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
841 DPMSG_ADDPLAYERTOGROUP msg;
842 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
844 msg.dpIdGroup = idGroup;
845 msg.dpIdPlayer = idPlayer;
847 /* FIXME: Correct to just use send effectively? */
848 /* FIXME: Should size include data w/ message or just message "header" */
849 /* FIXME: Check return code */
850 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
853 return DP_OK;
856 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
857 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
859 ICOM_THIS(IDirectPlay2Impl,iface);
860 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
863 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
864 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
866 ICOM_THIS(IDirectPlay2Impl,iface);
867 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
870 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
872 HRESULT hr = DP_OK;
874 TRACE("(%p)->(%u)\n", This, bAnsi );
876 /* FIXME: Need to find a new host I assume (how?) */
877 /* FIXME: Need to destroy all local groups */
878 /* FIXME: Need to migrate all remotely visible players to the new host */
880 /* Invoke the SP callback to inform of session close */
881 if( This->dp2->spData.lpCB->CloseEx )
883 DPSP_CLOSEDATA data;
885 TRACE( "Calling SP CloseEx\n" );
887 data.lpISP = This->dp2->spData.lpISP;
889 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
892 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
894 TRACE( "Calling SP Close (obsolete interface)\n" );
896 hr = (*This->dp2->spData.lpCB->Close)();
899 return hr;
902 static HRESULT WINAPI DirectPlay2AImpl_Close
903 ( LPDIRECTPLAY2A iface )
905 ICOM_THIS(IDirectPlay2Impl,iface);
906 return DP_IF_Close( This, TRUE );
909 static HRESULT WINAPI DirectPlay2WImpl_Close
910 ( LPDIRECTPLAY2 iface )
912 ICOM_THIS(IDirectPlay2Impl,iface);
913 return DP_IF_Close( This, FALSE );
916 static
917 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, LPDPID lpid,
918 LPDPNAME lpName, DWORD dwFlags,
919 DPID idParent, BOOL bAnsi )
921 lpGroupData lpGData;
923 /* Allocate the new space and add to end of high level group list */
924 lpGData = (lpGroupData) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
925 sizeof( *lpGData ) );
927 if( lpGData == NULL )
929 return NULL;
932 DPQ_INIT(lpGData->groups);
933 DPQ_INIT(lpGData->players);
935 /* Set the desired player ID - no sanity checking to see if it exists */
936 lpGData->dpid = *lpid;
938 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
940 /* FIXME: Should we check that the parent exists? */
941 lpGData->parent = idParent;
943 /* FIXME: Should we validate the dwFlags? */
944 lpGData->dwFlags = dwFlags;
946 TRACE( "Created group id 0x%08lx\n", *lpid );
948 return lpGData;
951 /* This method assumes that all links to it are already deleted */
952 static void
953 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
955 lpGroupList lpGList;
957 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
959 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
961 if( lpGList == NULL )
963 ERR( "DPID 0x%08lx not found\n", dpid );
964 return;
967 if( --(lpGList->lpGData->uRef) )
969 FIXME( "Why is this not the last reference to group?\n" );
970 DebugBreak();
973 /* Delete player */
974 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
975 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
977 /* Remove and Delete Player List object */
978 HeapFree( GetProcessHeap(), 0, lpGList );
982 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
984 lpGroupList lpGroups;
986 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
988 if( dpid == DPID_SYSTEM_GROUP )
990 return This->dp2->lpSysGroup;
992 else
994 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
997 if( lpGroups == NULL )
999 return NULL;
1002 return lpGroups->lpGData;
1005 static HRESULT WINAPI DP_IF_CreateGroup
1006 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
1007 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
1008 DWORD dwFlags, BOOL bAnsi )
1010 lpGroupData lpGData;
1012 TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
1013 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
1014 dwFlags, bAnsi );
1016 /* If the name is not specified, we must provide one */
1017 if( DPID_UNKNOWN == *lpidGroup )
1019 /* If we are the name server, we decide on the group ids. If not, we
1020 * must ask for one before attempting a creation.
1022 if( This->dp2->bHostInterface )
1024 *lpidGroup = DP_NextObjectId();
1026 else
1028 *lpidGroup = DP_GetRemoteNextObjectId();
1032 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1033 DPID_NOPARENT_GROUP, bAnsi );
1035 if( lpGData == NULL )
1037 return DPERR_CANTADDPLAYER; /* yes player not group */
1040 if( DPID_SYSTEM_GROUP == *lpidGroup )
1042 This->dp2->lpSysGroup = lpGData;
1043 TRACE( "Inserting system group\n" );
1045 else
1047 /* Insert into the system group */
1048 lpGroupList lpGroup = (lpGroupList) HeapAlloc( GetProcessHeap(),
1049 HEAP_ZERO_MEMORY,
1050 sizeof( *lpGroup ) );
1051 lpGroup->lpGData = lpGData;
1053 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1056 /* Something is now referencing this data */
1057 lpGData->uRef++;
1059 /* Set all the important stuff for the group */
1060 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1062 /* FIXME: We should only create the system group if GetCaps returns
1063 * DPCAPS_GROUPOPTIMIZED.
1066 /* Let the SP know that we've created this group */
1067 if( This->dp2->spData.lpCB->CreateGroup )
1069 DPSP_CREATEGROUPDATA data;
1070 DWORD dwCreateFlags = 0;
1072 TRACE( "Calling SP CreateGroup\n" );
1074 if( *lpidGroup == DPID_NOPARENT_GROUP )
1075 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1077 if( lpMsgHdr == NULL )
1078 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1080 if( dwFlags & DPGROUP_HIDDEN )
1081 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1083 data.idGroup = *lpidGroup;
1084 data.dwFlags = dwCreateFlags;
1085 data.lpSPMessageHeader = lpMsgHdr;
1086 data.lpISP = This->dp2->spData.lpISP;
1088 (*This->dp2->spData.lpCB->CreateGroup)( &data );
1091 /* Inform all other peers of the creation of a new group. If there are
1092 * no peers keep this event quiet.
1093 * Also if this message was sent to us, don't rebroadcast.
1095 if( ( lpMsgHdr == NULL ) &&
1096 This->dp2->lpSessionDesc &&
1097 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1099 DPMSG_CREATEPLAYERORGROUP msg;
1100 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1102 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
1103 msg.dpId = *lpidGroup;
1104 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1105 msg.lpData = lpData;
1106 msg.dwDataSize = dwDataSize;
1107 msg.dpnName = *lpGroupName;
1108 msg.dpIdParent = DPID_NOPARENT_GROUP;
1109 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1111 /* FIXME: Correct to just use send effectively? */
1112 /* FIXME: Should size include data w/ message or just message "header" */
1113 /* FIXME: Check return code */
1114 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
1115 0, 0, NULL, NULL, bAnsi );
1118 return DP_OK;
1121 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
1122 ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1123 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1125 *lpidGroup = DPID_UNKNOWN;
1127 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1128 lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
1131 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1132 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1133 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1135 *lpidGroup = DPID_UNKNOWN;
1137 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1138 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
1142 static void
1143 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1144 LPVOID lpData, DWORD dwDataSize )
1146 /* Clear out the data with this player */
1147 if( ( dwFlags & DPSET_LOCAL ) &&
1148 ( lpGData->dwLocalDataSize != 0 )
1151 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1152 lpGData->lpLocalData = NULL;
1153 lpGData->dwLocalDataSize = 0;
1155 if( ( dwFlags & DPSET_REMOTE ) &&
1156 ( lpGData->dwRemoteDataSize != 0 )
1159 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1160 lpGData->lpRemoteData = NULL;
1161 lpGData->dwRemoteDataSize = 0;
1164 /* Reallocate for new data */
1165 if( lpData != NULL )
1167 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1168 sizeof( dwDataSize ) );
1169 CopyMemory( lpNewData, lpData, dwDataSize );
1171 if( dwFlags & DPSET_REMOTE )
1173 lpGData->lpRemoteData = lpNewData;
1174 lpGData->dwRemoteDataSize = dwDataSize;
1177 if( dwFlags & DPSET_LOCAL )
1179 lpGData->lpLocalData = lpData;
1180 lpGData->dwLocalDataSize = dwDataSize;
1186 /* This function will just create the storage for the new player. */
1187 static
1188 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1189 LPDPNAME lpName, DWORD dwFlags,
1190 HANDLE hEvent, BOOL bAnsi )
1192 lpPlayerData lpPData;
1194 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1196 /* Allocate the storage for the player and associate it with list element */
1197 lpPData = (lpPlayerData) HeapAlloc( GetProcessHeap(),
1198 HEAP_ZERO_MEMORY,
1199 sizeof( *lpPData ) );
1200 if( lpPData == NULL )
1202 return NULL;
1205 /* Set the desired player ID */
1206 lpPData->dpid = *lpid;
1208 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1210 lpPData->dwFlags = dwFlags;
1212 /* If we were given an event handle, duplicate it */
1213 if( hEvent != 0 )
1215 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1216 GetCurrentProcess(), &lpPData->hEvent,
1217 0, FALSE, DUPLICATE_SAME_ACCESS )
1220 /* FIXME: Memory leak */
1221 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1225 /* Initialize the SP data section */
1226 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1228 TRACE( "Created player id 0x%08lx\n", *lpid );
1230 return lpPData;
1233 /* Delete the contents of the DPNAME struct */
1234 static void
1235 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1237 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1238 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1241 /* This method assumes that all links to it are already deleted */
1242 static void
1243 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1245 lpPlayerList lpPList;
1247 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
1249 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1251 if( lpPList == NULL )
1253 ERR( "DPID 0x%08lx not found\n", dpid );
1254 return;
1257 /* Verify that this is the last reference to the data */
1258 if( --(lpPList->lpPData->uRef) )
1260 FIXME( "Why is this not the last reference to player?\n" );
1261 DebugBreak();
1264 /* Delete player */
1265 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1267 CloseHandle( lpPList->lpPData->hEvent );
1268 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1270 /* Delete Player List object */
1271 HeapFree( GetProcessHeap(), 0, lpPList );
1274 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1276 lpPlayerList lpPlayers;
1278 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
1280 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1282 return lpPlayers;
1285 /* Basic area for Dst must already be allocated */
1286 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi )
1288 if( lpSrc == NULL )
1290 ZeroMemory( lpDst, sizeof( *lpDst ) );
1291 lpDst->dwSize = sizeof( *lpDst );
1292 return TRUE;
1295 if( lpSrc->dwSize != sizeof( *lpSrc) )
1297 return FALSE;
1300 /* Delete any existing pointers */
1301 if( lpDst->u1.lpszShortNameA )
1303 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1306 if( lpDst->u2.lpszLongNameA )
1308 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1311 /* Copy as required */
1312 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1314 if( bAnsi )
1316 if( lpSrc->u1.lpszShortNameA )
1318 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1319 strlen(lpSrc->u1.lpszShortNameA)+1 );
1320 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1322 if( lpSrc->u2.lpszLongNameA )
1324 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1325 strlen(lpSrc->u2.lpszLongNameA)+1 );
1326 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1329 else
1331 if( lpSrc->u1.lpszShortNameA )
1333 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1334 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1335 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1337 if( lpSrc->u2.lpszLongNameA )
1339 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1340 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1341 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1345 return TRUE;
1348 static void
1349 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1350 LPVOID lpData, DWORD dwDataSize )
1352 /* Clear out the data with this player */
1353 if( ( dwFlags & DPSET_LOCAL ) &&
1354 ( lpPData->dwLocalDataSize != 0 )
1357 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1358 lpPData->lpLocalData = NULL;
1359 lpPData->dwLocalDataSize = 0;
1361 if( ( dwFlags & DPSET_REMOTE ) &&
1362 ( lpPData->dwRemoteDataSize != 0 )
1365 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1366 lpPData->lpRemoteData = NULL;
1367 lpPData->dwRemoteDataSize = 0;
1370 /* Reallocate for new data */
1371 if( lpData != NULL )
1373 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1374 sizeof( dwDataSize ) );
1375 CopyMemory( lpNewData, lpData, dwDataSize );
1377 if( dwFlags & DPSET_REMOTE )
1379 lpPData->lpRemoteData = lpNewData;
1380 lpPData->dwRemoteDataSize = dwDataSize;
1383 if( dwFlags & DPSET_LOCAL )
1385 lpPData->lpLocalData = lpData;
1386 lpPData->dwLocalDataSize = dwDataSize;
1392 static HRESULT WINAPI DP_IF_CreatePlayer
1393 ( IDirectPlay2Impl* This,
1394 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1395 LPDPID lpidPlayer,
1396 LPDPNAME lpPlayerName,
1397 HANDLE hEvent,
1398 LPVOID lpData,
1399 DWORD dwDataSize,
1400 DWORD dwFlags,
1401 BOOL bAnsi )
1403 HRESULT hr = DP_OK;
1404 lpPlayerData lpPData;
1405 lpPlayerList lpPList;
1406 DWORD dwCreateFlags = 0;
1408 TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
1409 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1410 dwDataSize, dwFlags, bAnsi );
1412 if( dwFlags == 0 )
1414 dwFlags = DPPLAYER_SPECTATOR;
1417 if( lpidPlayer == NULL )
1419 return DPERR_INVALIDPARAMS;
1423 /* Determine the creation flags for the player. These will be passed
1424 * to the name server if requesting a player id and to the SP when
1425 * informing it of the player creation
1428 if( dwFlags & DPPLAYER_SERVERPLAYER )
1430 if( *lpidPlayer == DPID_SERVERPLAYER )
1432 /* Server player for the host interface */
1433 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1435 else if( *lpidPlayer == DPID_NAME_SERVER )
1437 /* Name server - master of everything */
1438 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1440 else
1442 /* Server player for a non host interface */
1443 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1447 if( lpMsgHdr == NULL )
1448 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1451 /* Verify we know how to handle all the flags */
1452 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1453 ( dwFlags & DPPLAYER_SPECTATOR )
1457 /* Assume non fatal failure */
1458 ERR( "unknown dwFlags = 0x%08lx\n", dwFlags );
1461 /* If the name is not specified, we must provide one */
1462 if( *lpidPlayer == DPID_UNKNOWN )
1464 /* If we are the session master, we dish out the group/player ids */
1465 if( This->dp2->bHostInterface )
1467 *lpidPlayer = DP_NextObjectId();
1469 else
1471 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1473 if( FAILED(hr) )
1475 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1476 return hr;
1480 else
1482 /* FIXME: Would be nice to perhaps verify that we don't already have
1483 * this player.
1487 /* FIXME: Should we be storing these dwFlags or the creation ones? */
1488 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags,
1489 hEvent, bAnsi );
1491 if( lpPData == NULL )
1493 return DPERR_CANTADDPLAYER;
1496 /* Create the list object and link it in */
1497 lpPList = (lpPlayerList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1498 sizeof( *lpPList ) );
1499 if( lpPList == NULL )
1501 FIXME( "Memory leak\n" );
1502 return DPERR_CANTADDPLAYER;
1505 lpPData->uRef = 1;
1506 lpPList->lpPData = lpPData;
1508 /* Add the player to the system group */
1509 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1511 /* Update the information and send it to all players in the session */
1512 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1514 /* Let the SP know that we've created this player */
1515 if( This->dp2->spData.lpCB->CreatePlayer )
1517 DPSP_CREATEPLAYERDATA data;
1519 data.idPlayer = *lpidPlayer;
1520 data.dwFlags = dwCreateFlags;
1521 data.lpSPMessageHeader = lpMsgHdr;
1522 data.lpISP = This->dp2->spData.lpISP;
1524 TRACE( "Calling SP CreatePlayer 0x%08lx: dwFlags: 0x%08lx lpMsgHdr: %p\n",
1525 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1527 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1530 if( FAILED(hr) )
1532 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1533 return hr;
1536 /* Now let the SP know that this player is a member of the system group */
1537 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1539 DPSP_ADDPLAYERTOGROUPDATA data;
1541 data.idPlayer = *lpidPlayer;
1542 data.idGroup = DPID_SYSTEM_GROUP;
1543 data.lpISP = This->dp2->spData.lpISP;
1545 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1547 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1550 if( FAILED(hr) )
1552 ERR( "Failed to add player to sys group with sp: %s\n",
1553 DPLAYX_HresultToString(hr) );
1554 return hr;
1557 #if 1
1558 if( This->dp2->bHostInterface == FALSE )
1560 /* Let the name server know about the creation of this player */
1561 /* FIXME: Is this only to be done for the creation of a server player or
1562 * is this used for regular players? If only for server players, move
1563 * this call to DP_SecureOpen(...);
1565 #if 0
1566 TRACE( "Sending message to self to get my addr\n" );
1567 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1568 #endif
1570 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1572 #else
1573 /* Inform all other peers of the creation of a new player. If there are
1574 * no peers keep this quiet.
1575 * Also, if this was a remote event, no need to rebroadcast it.
1577 if( ( lpMsgHdr == NULL ) &&
1578 This->dp2->lpSessionDesc &&
1579 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1581 DPMSG_CREATEPLAYERORGROUP msg;
1582 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1584 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1585 msg.dpId = *lpidPlayer;
1586 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1587 msg.lpData = lpData;
1588 msg.dwDataSize = dwDataSize;
1589 msg.dpnName = *lpPlayerName;
1590 msg.dpIdParent = DPID_NOPARENT_GROUP;
1591 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1593 /* FIXME: Correct to just use send effectively? */
1594 /* FIXME: Should size include data w/ message or just message "header" */
1595 /* FIXME: Check return code */
1596 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1597 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1599 #endif
1601 return hr;
1604 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1605 ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1606 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1608 ICOM_THIS(IDirectPlay2Impl,iface);
1610 if( dwFlags & DPPLAYER_SERVERPLAYER )
1612 *lpidPlayer = DPID_SERVERPLAYER;
1614 else
1616 *lpidPlayer = DPID_UNKNOWN;
1619 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1620 lpData, dwDataSize, dwFlags, TRUE );
1623 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1624 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1625 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1627 ICOM_THIS(IDirectPlay2Impl,iface);
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, FALSE );
1642 static DPID DP_GetRemoteNextObjectId(void)
1644 FIXME( ":stub\n" );
1646 /* Hack solution */
1647 return DP_NextObjectId();
1650 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
1651 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1652 DPID idPlayer, BOOL bAnsi )
1654 HRESULT hr = DP_OK;
1656 lpGroupData lpGData;
1657 lpPlayerList lpPList;
1659 TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n",
1660 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1662 /* Find the group */
1663 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1665 return DPERR_INVALIDGROUP;
1668 /* Find the player */
1669 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1671 return DPERR_INVALIDPLAYER;
1674 /* Remove the player shortcut from the group */
1675 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1677 if( lpPList == NULL )
1679 return DPERR_INVALIDPLAYER;
1682 /* One less reference */
1683 lpPList->lpPData->uRef--;
1685 /* Delete the Player List element */
1686 HeapFree( GetProcessHeap(), 0, lpPList );
1688 /* Inform the SP if they care */
1689 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1691 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1693 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1695 data.idPlayer = idPlayer;
1696 data.idGroup = idGroup;
1697 data.lpISP = This->dp2->spData.lpISP;
1699 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1702 /* Need to send a DELETEPLAYERFROMGROUP message */
1703 FIXME( "Need to send a message\n" );
1705 return hr;
1708 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1709 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1711 ICOM_THIS(IDirectPlay2Impl,iface);
1712 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1715 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1716 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1718 ICOM_THIS(IDirectPlay2Impl,iface);
1719 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1722 typedef struct _DPRGOPContext
1724 IDirectPlay3Impl* This;
1725 BOOL bAnsi;
1726 DPID idGroup;
1727 } DPRGOPContext, *lpDPRGOPContext;
1729 static BOOL CALLBACK
1730 cbRemoveGroupOrPlayer(
1731 DPID dpId,
1732 DWORD dwPlayerType,
1733 LPCDPNAME lpName,
1734 DWORD dwFlags,
1735 LPVOID lpContext )
1737 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1739 TRACE( "Removing element:0x%08lx (type:0x%08lx) from element:0x%08lx\n",
1740 dpId, dwPlayerType, lpCtxt->idGroup );
1742 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1744 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1745 dpId )
1749 ERR( "Unable to delete group 0x%08lx from group 0x%08lx\n",
1750 dpId, lpCtxt->idGroup );
1753 else
1755 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1756 NULL, lpCtxt->idGroup,
1757 dpId, lpCtxt->bAnsi )
1761 ERR( "Unable to delete player 0x%08lx from grp 0x%08lx\n",
1762 dpId, lpCtxt->idGroup );
1766 return TRUE; /* Continue enumeration */
1769 static HRESULT WINAPI DP_IF_DestroyGroup
1770 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1772 lpGroupData lpGData;
1773 DPRGOPContext context;
1775 FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n",
1776 This, lpMsgHdr, idGroup, bAnsi );
1778 /* Find the group */
1779 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1781 return DPERR_INVALIDPLAYER; /* yes player */
1784 context.This = (IDirectPlay3Impl*)This;
1785 context.bAnsi = bAnsi;
1786 context.idGroup = idGroup;
1788 /* Remove all players that this group has */
1789 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1790 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1792 /* Remove all links to groups that this group has since this is dp3 */
1793 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1794 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1796 /* Remove this group from the parent group - if it has one */
1797 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1798 ( lpGData->parent != DPID_SYSTEM_GROUP )
1801 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1802 idGroup );
1805 /* Now delete this group data and list from the system group */
1806 DP_DeleteGroup( This, idGroup );
1808 /* Let the SP know that we've destroyed this group */
1809 if( This->dp2->spData.lpCB->DeleteGroup )
1811 DPSP_DELETEGROUPDATA data;
1813 FIXME( "data.dwFlags is incorrect\n" );
1815 data.idGroup = idGroup;
1816 data.dwFlags = 0;
1817 data.lpISP = This->dp2->spData.lpISP;
1819 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1822 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1824 return DP_OK;
1827 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1828 ( LPDIRECTPLAY2A iface, DPID idGroup )
1830 ICOM_THIS(IDirectPlay2Impl,iface);
1831 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1834 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1835 ( LPDIRECTPLAY2 iface, DPID idGroup )
1837 ICOM_THIS(IDirectPlay2Impl,iface);
1838 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1841 typedef struct _DPFAGContext
1843 IDirectPlay2Impl* This;
1844 DPID idPlayer;
1845 BOOL bAnsi;
1846 } DPFAGContext, *lpDPFAGContext;
1848 static HRESULT WINAPI DP_IF_DestroyPlayer
1849 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1851 DPFAGContext cbContext;
1853 FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n",
1854 This, lpMsgHdr, idPlayer, bAnsi );
1856 if( This->dp2->connectionInitialized == NO_PROVIDER )
1858 return DPERR_UNINITIALIZED;
1861 if( DP_FindPlayer( This, idPlayer ) == NULL )
1863 return DPERR_INVALIDPLAYER;
1866 /* FIXME: If the player is remote, we must be the host to delete this */
1868 cbContext.This = This;
1869 cbContext.idPlayer = idPlayer;
1870 cbContext.bAnsi = bAnsi;
1872 /* Find each group and call DeletePlayerFromGroup if the player is a
1873 member of the group */
1874 DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
1875 (LPVOID)&cbContext, DPENUMGROUPS_ALL, bAnsi );
1877 /* Now delete player and player list from the sys group */
1878 DP_DeletePlayer( This, idPlayer );
1880 /* Let the SP know that we've destroyed this group */
1881 if( This->dp2->spData.lpCB->DeletePlayer )
1883 DPSP_DELETEPLAYERDATA data;
1885 FIXME( "data.dwFlags is incorrect\n" );
1887 data.idPlayer = idPlayer;
1888 data.dwFlags = 0;
1889 data.lpISP = This->dp2->spData.lpISP;
1891 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1894 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1896 return DP_OK;
1899 static BOOL CALLBACK
1900 cbDeletePlayerFromAllGroups(
1901 DPID dpId,
1902 DWORD dwPlayerType,
1903 LPCDPNAME lpName,
1904 DWORD dwFlags,
1905 LPVOID lpContext )
1907 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1909 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1911 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
1912 lpCtxt->bAnsi );
1914 /* Enumerate all groups in this group since this will normally only
1915 * be called for top level groups
1917 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
1918 dpId, NULL,
1919 cbDeletePlayerFromAllGroups,
1920 (LPVOID)lpContext, DPENUMGROUPS_ALL,
1921 lpCtxt->bAnsi );
1924 else
1926 ERR( "Group callback has dwPlayerType = 0x%08lx\n", dwPlayerType );
1929 return TRUE;
1932 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
1933 ( LPDIRECTPLAY2A iface, DPID idPlayer )
1935 ICOM_THIS(IDirectPlay2Impl,iface);
1936 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1939 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1940 ( LPDIRECTPLAY2 iface, DPID idPlayer )
1942 ICOM_THIS(IDirectPlay2Impl,iface);
1943 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1946 static HRESULT WINAPI DP_IF_EnumGroupPlayers
1947 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1948 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1949 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1951 lpGroupData lpGData;
1952 lpPlayerList lpPList;
1954 FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n",
1955 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1956 lpContext, dwFlags, bAnsi );
1958 if( This->dp2->connectionInitialized == NO_PROVIDER )
1960 return DPERR_UNINITIALIZED;
1963 /* Find the group */
1964 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1966 return DPERR_INVALIDGROUP;
1969 if( DPQ_IS_EMPTY( lpGData->players ) )
1971 return DP_OK;
1974 lpPList = DPQ_FIRST( lpGData->players );
1976 /* Walk the players in this group */
1977 for( ;; )
1979 /* We do not enum the name server or app server as they are of no
1980 * concequence to the end user.
1982 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
1983 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
1987 /* FIXME: Need to add stuff for dwFlags checking */
1989 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1990 &lpPList->lpPData->name,
1991 lpPList->lpPData->dwFlags,
1992 lpContext )
1995 /* User requested break */
1996 return DP_OK;
2000 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
2002 break;
2005 lpPList = DPQ_NEXT( lpPList->players );
2008 return DP_OK;
2011 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
2012 ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
2013 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2014 LPVOID lpContext, DWORD dwFlags )
2016 ICOM_THIS(IDirectPlay2Impl,iface);
2017 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2018 lpEnumPlayersCallback2, lpContext,
2019 dwFlags, TRUE );
2022 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
2023 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
2024 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2025 LPVOID lpContext, DWORD dwFlags )
2027 ICOM_THIS(IDirectPlay2Impl,iface);
2028 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2029 lpEnumPlayersCallback2, lpContext,
2030 dwFlags, FALSE );
2033 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2034 static HRESULT WINAPI DP_IF_EnumGroups
2035 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2036 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2037 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2039 return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2040 DPID_SYSTEM_GROUP, lpguidInstance,
2041 lpEnumPlayersCallback2, lpContext,
2042 dwFlags, bAnsi );
2045 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2046 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2047 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2048 LPVOID lpContext, DWORD dwFlags )
2050 ICOM_THIS(IDirectPlay2Impl,iface);
2051 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2052 lpContext, dwFlags, TRUE );
2055 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2056 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2057 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2058 LPVOID lpContext, DWORD dwFlags )
2060 ICOM_THIS(IDirectPlay2Impl,iface);
2061 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2062 lpContext, dwFlags, FALSE );
2065 static HRESULT WINAPI DP_IF_EnumPlayers
2066 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2067 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2068 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2070 return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
2071 lpEnumPlayersCallback2, lpContext,
2072 dwFlags, bAnsi );
2075 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2076 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2077 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2078 LPVOID lpContext, DWORD dwFlags )
2080 ICOM_THIS(IDirectPlay2Impl,iface);
2081 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2082 lpContext, dwFlags, TRUE );
2085 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2086 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2087 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2088 LPVOID lpContext, DWORD dwFlags )
2090 ICOM_THIS(IDirectPlay2Impl,iface);
2091 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2092 lpContext, dwFlags, FALSE );
2095 /* This function should call the registered callback function that the user
2096 passed into EnumSessions for each entry available.
2098 static void DP_InvokeEnumSessionCallbacks
2099 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2100 LPVOID lpNSInfo,
2101 DWORD dwTimeout,
2102 LPVOID lpContext )
2104 LPDPSESSIONDESC2 lpSessionDesc;
2106 FIXME( ": not checking for conditions\n" );
2108 /* Not sure if this should be pruning but it's convenient */
2109 NS_PruneSessionCache( lpNSInfo );
2111 NS_ResetSessionEnumeration( lpNSInfo );
2113 /* Enumerate all sessions */
2114 /* FIXME: Need to indicate ANSI */
2115 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2117 TRACE( "EnumSessionsCallback2 invoked\n" );
2118 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2120 return;
2124 /* Invoke one last time to indicate that there is no more to come */
2125 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2128 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2130 EnumSessionAsyncCallbackData* data = (EnumSessionAsyncCallbackData*)lpContext;
2131 HANDLE hSuicideRequest = data->hSuicideRequest;
2132 DWORD dwTimeout = data->dwTimeout;
2134 TRACE( "Thread started with timeout = 0x%08lx\n", dwTimeout );
2136 for( ;; )
2138 HRESULT hr;
2140 /* Sleep up to dwTimeout waiting for request to terminate thread */
2141 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2143 TRACE( "Thread terminating on terminate request\n" );
2144 break;
2147 /* Now resend the enum request */
2148 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2149 data->dwEnumSessionFlags,
2150 data->lpSpData );
2152 if( FAILED(hr) )
2154 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2155 /* FIXME: Should we kill this thread? How to inform the main thread? */
2160 TRACE( "Thread terminating\n" );
2162 /* Clean up the thread data */
2163 CloseHandle( hSuicideRequest );
2164 HeapFree( GetProcessHeap(), 0, lpContext );
2166 /* FIXME: Need to have some notification to main app thread that this is
2167 * dead. It would serve two purposes. 1) allow sync on termination
2168 * so that we don't actually send something to ourselves when we
2169 * become name server (race condition) and 2) so that if we die
2170 * abnormally something else will be able to tell.
2173 return 1;
2176 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
2178 /* Does a thread exist? If so we were doing an async enum session */
2179 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2181 TRACE( "Killing EnumSession thread %p\n",
2182 This->dp2->hEnumSessionThread );
2184 /* Request that the thread kill itself nicely */
2185 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2186 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2188 /* We no longer need to know about the thread */
2189 CloseHandle( This->dp2->hEnumSessionThread );
2191 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2195 static HRESULT WINAPI DP_IF_EnumSessions
2196 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2197 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2198 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2200 HRESULT hr = DP_OK;
2202 TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx,%u)\n",
2203 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2204 bAnsi );
2206 /* Can't enumerate if the interface is already open */
2207 if( This->dp2->bConnectionOpen )
2209 return DPERR_GENERIC;
2212 #if 1
2213 /* The loading of a lobby provider _seems_ to require a backdoor loading
2214 * of the service provider to also associate with this DP object. This is
2215 * because the app doesn't seem to have to call EnumConnections and
2216 * InitializeConnection for the SP before calling this method. As such
2217 * we'll do their dirty work for them with a quick hack so as to always
2218 * load the TCP/IP service provider.
2220 * The correct solution would seem to involve creating a dialog box which
2221 * contains the possible SPs. These dialog boxes most likely follow SDK
2222 * examples.
2224 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2226 LPVOID lpConnection;
2227 DWORD dwSize;
2229 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2231 if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2233 ERR( "Can't build compound addr\n" );
2234 return DPERR_GENERIC;
2237 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2238 0, bAnsi );
2239 if( FAILED(hr) )
2241 return hr;
2244 /* Free up the address buffer */
2245 HeapFree( GetProcessHeap(), 0, lpConnection );
2247 /* The SP is now initialized */
2248 This->dp2->bSPInitialized = TRUE;
2250 #endif
2253 /* Use the service provider default? */
2254 if( dwTimeout == 0 )
2256 DPCAPS spCaps;
2257 spCaps.dwSize = sizeof( spCaps );
2259 DP_IF_GetCaps( This, &spCaps, 0 );
2260 dwTimeout = spCaps.dwTimeout;
2262 /* The service provider doesn't provide one either! */
2263 if( dwTimeout == 0 )
2265 /* Provide the TCP/IP default */
2266 dwTimeout = DPMSG_WAIT_5_SECS;
2270 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2272 DP_KillEnumSessionThread( This );
2273 return hr;
2276 /* FIXME: Interface locking sucks in this method */
2277 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2279 /* Enumerate everything presently in the local session cache */
2280 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2281 This->dp2->lpNameServerData, dwTimeout,
2282 lpContext );
2285 /* See if we've already created a thread to service this interface */
2286 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2288 DWORD dwThreadId;
2290 /* Send the first enum request inline since the user may cancel a dialog
2291 * if one is presented. Also, may also have a connecting return code.
2293 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2294 dwFlags, &This->dp2->spData );
2296 if( !FAILED(hr) )
2298 EnumSessionAsyncCallbackData* lpData
2299 = (EnumSessionAsyncCallbackData*)HeapAlloc( GetProcessHeap(),
2300 HEAP_ZERO_MEMORY,
2301 sizeof( *lpData ) );
2302 /* FIXME: need to kill the thread on object deletion */
2303 lpData->lpSpData = &This->dp2->spData;
2305 CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
2306 lpData->dwEnumSessionFlags = dwFlags;
2307 lpData->dwTimeout = dwTimeout;
2309 This->dp2->hKillEnumSessionThreadEvent =
2310 CreateEventA( NULL, TRUE, FALSE, NULL );
2312 if( !DuplicateHandle( GetCurrentProcess(),
2313 This->dp2->hKillEnumSessionThreadEvent,
2314 GetCurrentProcess(),
2315 &lpData->hSuicideRequest,
2316 0, FALSE, DUPLICATE_SAME_ACCESS )
2319 ERR( "Can't duplicate thread killing handle\n" );
2322 TRACE( ": creating EnumSessionsRequest thread\n" );
2324 This->dp2->hEnumSessionThread = CreateThread( NULL,
2326 DP_EnumSessionsSendAsyncRequestThread,
2327 lpData,
2329 &dwThreadId );
2333 else
2335 /* Invalidate the session cache for the interface */
2336 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2338 /* Send the broadcast for session enumeration */
2339 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2340 dwFlags,
2341 &This->dp2->spData );
2344 SleepEx( dwTimeout, FALSE );
2346 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2347 This->dp2->lpNameServerData, dwTimeout,
2348 lpContext );
2351 return hr;
2354 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2355 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2356 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2357 LPVOID lpContext, DWORD dwFlags )
2359 ICOM_THIS(IDirectPlay2Impl,iface);
2360 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2361 lpContext, dwFlags, TRUE );
2364 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2365 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2366 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2367 LPVOID lpContext, DWORD dwFlags )
2369 ICOM_THIS(IDirectPlay2Impl,iface);
2370 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2371 lpContext, dwFlags, FALSE );
2374 static HRESULT WINAPI DP_IF_GetPlayerCaps
2375 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2376 DWORD dwFlags )
2378 DPSP_GETCAPSDATA data;
2380 TRACE("(%p)->(0x%08lx,%p,0x%08lx)\n", This, idPlayer, lpDPCaps, dwFlags);
2382 /* Query the service provider */
2383 data.idPlayer = idPlayer;
2384 data.dwFlags = dwFlags;
2385 data.lpCaps = lpDPCaps;
2386 data.lpISP = This->dp2->spData.lpISP;
2388 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2391 static HRESULT WINAPI DP_IF_GetCaps
2392 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2394 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2397 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2398 ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2400 ICOM_THIS(IDirectPlay2Impl,iface);
2401 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2404 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2405 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2407 ICOM_THIS(IDirectPlay2Impl,iface);
2408 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2411 static HRESULT WINAPI DP_IF_GetGroupData
2412 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2413 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2415 lpGroupData lpGData;
2416 DWORD dwRequiredBufferSize;
2417 LPVOID lpCopyDataFrom;
2419 TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n",
2420 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2422 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2424 return DPERR_INVALIDGROUP;
2427 /* How much buffer is required? */
2428 if( dwFlags & DPSET_REMOTE )
2430 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2431 lpCopyDataFrom = lpGData->lpRemoteData;
2433 else if( dwFlags & DPSET_LOCAL )
2435 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2436 lpCopyDataFrom = lpGData->lpLocalData;
2438 else
2440 ERR( "Neither local or remote data requested!?!\n" );
2441 dwRequiredBufferSize = 0;
2442 lpCopyDataFrom = NULL;
2445 /* Is the user requesting to know how big a buffer is required? */
2446 if( ( lpData == NULL ) ||
2447 ( *lpdwDataSize < dwRequiredBufferSize )
2450 *lpdwDataSize = dwRequiredBufferSize;
2451 return DPERR_BUFFERTOOSMALL;
2454 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2456 return DP_OK;
2459 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2460 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2461 LPDWORD lpdwDataSize, DWORD dwFlags )
2463 ICOM_THIS(IDirectPlay2Impl,iface);
2464 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2465 dwFlags, TRUE );
2468 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2469 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2470 LPDWORD lpdwDataSize, DWORD dwFlags )
2472 ICOM_THIS(IDirectPlay2Impl,iface);
2473 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2474 dwFlags, FALSE );
2477 static HRESULT WINAPI DP_IF_GetGroupName
2478 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2479 LPDWORD lpdwDataSize, BOOL bAnsi )
2481 lpGroupData lpGData;
2482 LPDPNAME lpName = (LPDPNAME)lpData;
2483 DWORD dwRequiredDataSize;
2485 FIXME("(%p)->(0x%08lx,%p,%p,%u) ANSI ignored\n",
2486 This, idGroup, lpData, lpdwDataSize, bAnsi );
2488 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2490 return DPERR_INVALIDGROUP;
2493 dwRequiredDataSize = lpGData->name.dwSize;
2495 if( lpGData->name.u1.lpszShortNameA )
2497 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2500 if( lpGData->name.u2.lpszLongNameA )
2502 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2505 if( ( lpData == NULL ) ||
2506 ( *lpdwDataSize < dwRequiredDataSize )
2509 *lpdwDataSize = dwRequiredDataSize;
2510 return DPERR_BUFFERTOOSMALL;
2513 /* Copy the structure */
2514 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2516 if( lpGData->name.u1.lpszShortNameA )
2518 strcpy( ((BYTE*)lpName)+lpGData->name.dwSize,
2519 lpGData->name.u1.lpszShortNameA );
2521 else
2523 lpName->u1.lpszShortNameA = NULL;
2526 if( lpGData->name.u1.lpszShortNameA )
2528 strcpy( ((BYTE*)lpName)+lpGData->name.dwSize,
2529 lpGData->name.u2.lpszLongNameA );
2531 else
2533 lpName->u2.lpszLongNameA = NULL;
2536 return DP_OK;
2539 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2540 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2541 LPDWORD lpdwDataSize )
2543 ICOM_THIS(IDirectPlay2Impl,iface);
2544 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2547 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2548 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2549 LPDWORD lpdwDataSize )
2551 ICOM_THIS(IDirectPlay2Impl,iface);
2552 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2555 static HRESULT WINAPI DP_IF_GetMessageCount
2556 ( IDirectPlay2Impl* This, DPID idPlayer,
2557 LPDWORD lpdwCount, BOOL bAnsi )
2559 FIXME("(%p)->(0x%08lx,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2560 return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2561 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2562 bAnsi );
2565 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2566 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2568 ICOM_THIS(IDirectPlay2Impl,iface);
2569 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2572 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2573 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2575 ICOM_THIS(IDirectPlay2Impl,iface);
2576 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2579 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2580 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2582 ICOM_THIS(IDirectPlay2Impl,iface);
2583 FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2584 return DP_OK;
2587 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2588 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2590 ICOM_THIS(IDirectPlay2Impl,iface);
2591 FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2592 return DP_OK;
2595 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2596 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2597 DWORD dwFlags )
2599 ICOM_THIS(IDirectPlay2Impl,iface);
2600 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2603 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2604 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2605 DWORD dwFlags )
2607 ICOM_THIS(IDirectPlay2Impl,iface);
2608 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2611 static HRESULT WINAPI DP_IF_GetPlayerData
2612 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2613 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2615 lpPlayerList lpPList;
2616 DWORD dwRequiredBufferSize;
2617 LPVOID lpCopyDataFrom;
2619 TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n",
2620 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2622 if( This->dp2->connectionInitialized == NO_PROVIDER )
2624 return DPERR_UNINITIALIZED;
2627 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2629 return DPERR_INVALIDPLAYER;
2632 /* How much buffer is required? */
2633 if( dwFlags & DPSET_REMOTE )
2635 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2636 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2638 else if( dwFlags & DPSET_LOCAL )
2640 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2641 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2643 else
2645 ERR( "Neither local or remote data requested!?!\n" );
2646 dwRequiredBufferSize = 0;
2647 lpCopyDataFrom = NULL;
2650 /* Is the user requesting to know how big a buffer is required? */
2651 if( ( lpData == NULL ) ||
2652 ( *lpdwDataSize < dwRequiredBufferSize )
2655 *lpdwDataSize = dwRequiredBufferSize;
2656 return DPERR_BUFFERTOOSMALL;
2659 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2661 return DP_OK;
2664 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2665 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2666 LPDWORD lpdwDataSize, DWORD dwFlags )
2668 ICOM_THIS(IDirectPlay2Impl,iface);
2669 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2670 dwFlags, TRUE );
2673 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2674 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2675 LPDWORD lpdwDataSize, DWORD dwFlags )
2677 ICOM_THIS(IDirectPlay2Impl,iface);
2678 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2679 dwFlags, FALSE );
2682 static HRESULT WINAPI DP_IF_GetPlayerName
2683 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2684 LPDWORD lpdwDataSize, BOOL bAnsi )
2686 lpPlayerList lpPList;
2687 LPDPNAME lpName = (LPDPNAME)lpData;
2688 DWORD dwRequiredDataSize;
2690 FIXME( "(%p)->(0x%08lx,%p,%p,%u): ANSI \n",
2691 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2693 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2695 return DPERR_INVALIDPLAYER;
2698 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2700 if( lpPList->lpPData->name.u1.lpszShortNameA )
2702 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2705 if( lpPList->lpPData->name.u2.lpszLongNameA )
2707 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2710 if( ( lpData == NULL ) ||
2711 ( *lpdwDataSize < dwRequiredDataSize )
2714 *lpdwDataSize = dwRequiredDataSize;
2715 return DPERR_BUFFERTOOSMALL;
2718 /* Copy the structure */
2719 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2721 if( lpPList->lpPData->name.u1.lpszShortNameA )
2723 strcpy( ((BYTE*)lpName)+lpPList->lpPData->name.dwSize,
2724 lpPList->lpPData->name.u1.lpszShortNameA );
2726 else
2728 lpName->u1.lpszShortNameA = NULL;
2731 if( lpPList->lpPData->name.u1.lpszShortNameA )
2733 strcpy( ((BYTE*)lpName)+lpPList->lpPData->name.dwSize,
2734 lpPList->lpPData->name.u2.lpszLongNameA );
2736 else
2738 lpName->u2.lpszLongNameA = NULL;
2741 return DP_OK;
2744 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2745 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2746 LPDWORD lpdwDataSize )
2748 ICOM_THIS(IDirectPlay2Impl,iface);
2749 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2752 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2753 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2754 LPDWORD lpdwDataSize )
2756 ICOM_THIS(IDirectPlay2Impl,iface);
2757 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2760 static HRESULT WINAPI DP_GetSessionDesc
2761 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2762 BOOL bAnsi )
2764 DWORD dwRequiredSize;
2766 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2768 if( This->dp2->connectionInitialized == NO_PROVIDER )
2770 return DPERR_UNINITIALIZED;
2773 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2775 return DPERR_INVALIDPARAMS;
2778 /* FIXME: Get from This->dp2->lpSessionDesc */
2779 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2781 if ( ( lpData == NULL ) ||
2782 ( *lpdwDataSize < dwRequiredSize )
2785 *lpdwDataSize = dwRequiredSize;
2786 return DPERR_BUFFERTOOSMALL;
2789 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2791 return DP_OK;
2794 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2795 ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2797 ICOM_THIS(IDirectPlay2Impl,iface);
2798 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2801 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2802 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2804 ICOM_THIS(IDirectPlay2Impl,iface);
2805 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2808 /* Intended only for COM compatibility. Always returns an error. */
2809 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2810 ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2812 ICOM_THIS(IDirectPlay2Impl,iface);
2813 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2814 return DPERR_ALREADYINITIALIZED;
2817 /* Intended only for COM compatibility. Always returns an error. */
2818 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2819 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2821 ICOM_THIS(IDirectPlay2Impl,iface);
2822 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2823 return DPERR_ALREADYINITIALIZED;
2827 static HRESULT WINAPI DP_SecureOpen
2828 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2829 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2830 BOOL bAnsi )
2832 HRESULT hr = DP_OK;
2834 FIXME( "(%p)->(%p,0x%08lx,%p,%p): partial stub\n",
2835 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2837 if( This->dp2->bConnectionOpen )
2839 TRACE( ": rejecting already open connection.\n" );
2840 return DPERR_ALREADYINITIALIZED;
2843 /* If we're enumerating, kill the thread */
2844 DP_KillEnumSessionThread( This );
2846 if( dwFlags & DPOPEN_CREATE )
2848 /* Rightoo - this computer is the host and the local computer needs to be
2849 the name server so that others can join this session */
2850 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2852 This->dp2->bHostInterface = TRUE;
2854 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2855 if( FAILED( hr ) )
2857 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2858 return hr;
2862 /* Invoke the conditional callback for the service provider */
2863 if( This->dp2->spData.lpCB->Open )
2865 DPSP_OPENDATA data;
2867 FIXME( "Not all data fields are correct. Need new parameter\n" );
2869 data.bCreate = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
2870 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2871 : NS_GetNSAddr( This->dp2->lpNameServerData );
2872 data.lpISP = This->dp2->spData.lpISP;
2873 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
2874 data.dwOpenFlags = dwFlags;
2875 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2877 hr = (*This->dp2->spData.lpCB->Open)(&data);
2878 if( FAILED( hr ) )
2880 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2881 return hr;
2886 /* Create the system group of which everything is a part of */
2887 DPID systemGroup = DPID_SYSTEM_GROUP;
2889 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2890 NULL, 0, 0, TRUE );
2894 if( dwFlags & DPOPEN_JOIN )
2896 DPID dpidServerId = DPID_UNKNOWN;
2898 /* Create the server player for this interface. This way we can receive
2899 * messages for this session.
2901 /* FIXME: I suppose that we should be setting an event for a receive
2902 * type of thing. That way the messaging thread could know to wake
2903 * up. DPlay would then trigger the hEvent for the player the
2904 * message is directed to.
2906 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2908 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2911 else if( dwFlags & DPOPEN_CREATE )
2913 DPID dpidNameServerId = DPID_NAME_SERVER;
2915 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2916 0, DPPLAYER_SERVERPLAYER, bAnsi );
2919 if( FAILED(hr) )
2921 ERR( "Couldn't create name server/system player: %s\n",
2922 DPLAYX_HresultToString(hr) );
2925 return hr;
2928 static HRESULT WINAPI DirectPlay2AImpl_Open
2929 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2931 ICOM_THIS(IDirectPlay2Impl,iface);
2932 TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
2933 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
2936 static HRESULT WINAPI DirectPlay2WImpl_Open
2937 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2939 ICOM_THIS(IDirectPlay2Impl,iface);
2940 TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
2941 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
2944 static HRESULT WINAPI DP_IF_Receive
2945 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2946 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2948 LPDPMSG lpMsg = NULL;
2950 FIXME( "(%p)->(%p,%p,0x%08lx,%p,%p,%u): stub\n",
2951 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2953 if( This->dp2->connectionInitialized == NO_PROVIDER )
2955 return DPERR_UNINITIALIZED;
2958 if( dwFlags == 0 )
2960 dwFlags = DPRECEIVE_ALL;
2963 /* If the lpData is NULL, we must be peeking the message */
2964 if( ( lpData == NULL ) &&
2965 !( dwFlags & DPRECEIVE_PEEK )
2968 return DPERR_INVALIDPARAMS;
2971 if( dwFlags & DPRECEIVE_ALL )
2973 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2975 if( !( dwFlags & DPRECEIVE_PEEK ) )
2977 FIXME( "Remove from queue\n" );
2980 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2981 ( dwFlags & DPRECEIVE_FROMPLAYER )
2984 FIXME( "Find matching message 0x%08lx\n", dwFlags );
2986 else
2988 ERR( "Hmmm..dwFlags 0x%08lx\n", dwFlags );
2991 if( lpMsg == NULL )
2993 return DPERR_NOMESSAGES;
2996 /* Copy into the provided buffer */
2997 CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
2999 return DP_OK;
3002 static HRESULT WINAPI DirectPlay2AImpl_Receive
3003 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
3004 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3006 ICOM_THIS(IDirectPlay2Impl,iface);
3007 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3008 lpData, lpdwDataSize, TRUE );
3011 static HRESULT WINAPI DirectPlay2WImpl_Receive
3012 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
3013 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3015 ICOM_THIS(IDirectPlay2Impl,iface);
3016 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3017 lpData, lpdwDataSize, FALSE );
3020 static HRESULT WINAPI DirectPlay2AImpl_Send
3021 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3023 ICOM_THIS(IDirectPlay2Impl,iface);
3024 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3025 0, 0, NULL, NULL, TRUE );
3028 static HRESULT WINAPI DirectPlay2WImpl_Send
3029 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3031 ICOM_THIS(IDirectPlay2Impl,iface);
3032 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3033 0, 0, NULL, NULL, FALSE );
3036 static HRESULT WINAPI DP_IF_SetGroupData
3037 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3038 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3040 lpGroupData lpGData;
3042 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n",
3043 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3045 /* Parameter check */
3046 if( ( lpData == NULL ) &&
3047 ( dwDataSize != 0 )
3050 return DPERR_INVALIDPARAMS;
3053 /* Find the pointer to the data for this player */
3054 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3056 return DPERR_INVALIDOBJECT;
3059 if( dwFlags & DPSET_REMOTE )
3061 FIXME( "Was this group created by this interface?\n" );
3062 /* FIXME: If this is a remote update need to allow it but not
3063 * send a message.
3067 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3069 /* FIXME: Only send a message if this group is local to the session otherwise
3070 * it will have been rejected above
3072 if( dwFlags & DPSET_REMOTE )
3074 FIXME( "Send msg?\n" );
3077 return DP_OK;
3080 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3081 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3082 DWORD dwDataSize, DWORD dwFlags )
3084 ICOM_THIS(IDirectPlay2Impl,iface);
3085 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3088 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3089 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3090 DWORD dwDataSize, DWORD dwFlags )
3092 ICOM_THIS(IDirectPlay2Impl,iface);
3093 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3096 static HRESULT WINAPI DP_IF_SetGroupName
3097 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3098 DWORD dwFlags, BOOL bAnsi )
3100 lpGroupData lpGData;
3102 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", This, idGroup,
3103 lpGroupName, dwFlags, bAnsi );
3105 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3107 return DPERR_INVALIDGROUP;
3110 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3112 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3113 FIXME( "Message not sent and dwFlags ignored\n" );
3115 return DP_OK;
3118 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3119 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3120 DWORD dwFlags )
3122 ICOM_THIS(IDirectPlay2Impl,iface);
3123 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3126 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3127 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3128 DWORD dwFlags )
3130 ICOM_THIS(IDirectPlay2Impl,iface);
3131 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3134 static HRESULT WINAPI DP_IF_SetPlayerData
3135 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3136 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3138 lpPlayerList lpPList;
3140 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n",
3141 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3143 /* Parameter check */
3144 if( ( lpData == NULL ) &&
3145 ( dwDataSize != 0 )
3148 return DPERR_INVALIDPARAMS;
3151 /* Find the pointer to the data for this player */
3152 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3154 return DPERR_INVALIDPLAYER;
3157 if( dwFlags & DPSET_REMOTE )
3159 FIXME( "Was this group created by this interface?\n" );
3160 /* FIXME: If this is a remote update need to allow it but not
3161 * send a message.
3165 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3167 if( dwFlags & DPSET_REMOTE )
3169 FIXME( "Send msg?\n" );
3172 return DP_OK;
3175 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3176 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3177 DWORD dwDataSize, DWORD dwFlags )
3179 ICOM_THIS(IDirectPlay2Impl,iface);
3180 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3181 dwFlags, TRUE );
3184 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3185 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3186 DWORD dwDataSize, DWORD dwFlags )
3188 ICOM_THIS(IDirectPlay2Impl,iface);
3189 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3190 dwFlags, FALSE );
3193 static HRESULT WINAPI DP_IF_SetPlayerName
3194 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3195 DWORD dwFlags, BOOL bAnsi )
3197 lpPlayerList lpPList;
3199 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n",
3200 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3202 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3204 return DPERR_INVALIDGROUP;
3207 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3209 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3210 FIXME( "Message not sent and dwFlags ignored\n" );
3212 return DP_OK;
3215 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3216 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3217 DWORD dwFlags )
3219 ICOM_THIS(IDirectPlay2Impl,iface);
3220 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3223 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3224 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3225 DWORD dwFlags )
3227 ICOM_THIS(IDirectPlay2Impl,iface);
3228 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3231 static HRESULT WINAPI DP_SetSessionDesc
3232 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3233 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3235 DWORD dwRequiredSize;
3236 LPDPSESSIONDESC2 lpTempSessDesc;
3238 TRACE( "(%p)->(%p,0x%08lx,%u,%u)\n",
3239 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3241 if( This->dp2->connectionInitialized == NO_PROVIDER )
3243 return DPERR_UNINITIALIZED;
3246 if( dwFlags )
3248 return DPERR_INVALIDPARAMS;
3251 /* Only the host is allowed to update the session desc */
3252 if( !This->dp2->bHostInterface )
3254 return DPERR_ACCESSDENIED;
3257 /* FIXME: Copy into This->dp2->lpSessionDesc */
3258 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3259 lpTempSessDesc = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(),
3260 HEAP_ZERO_MEMORY,
3261 dwRequiredSize );
3263 if( lpTempSessDesc == NULL )
3265 return DPERR_OUTOFMEMORY;
3268 /* Free the old */
3269 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3271 This->dp2->lpSessionDesc = lpTempSessDesc;
3273 /* Set the new */
3274 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3276 /* If this is an external invocation of the interface, we should be
3277 * letting everyone know that things have changed. Otherwise this is
3278 * just an initialization and it doesn't need to be propagated.
3280 if( !bInitial )
3282 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3285 return DP_OK;
3288 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3289 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3291 ICOM_THIS(IDirectPlay2Impl,iface);
3292 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3295 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3296 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3298 ICOM_THIS(IDirectPlay2Impl,iface);
3299 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3302 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3303 DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3305 DWORD dwSize = 0;
3307 if( lpSessDesc == NULL )
3309 /* Hmmm..don't need any size? */
3310 ERR( "NULL lpSessDesc\n" );
3311 return dwSize;
3314 dwSize += sizeof( *lpSessDesc );
3316 if( bAnsi )
3318 if( lpSessDesc->u1.lpszSessionNameA )
3320 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3323 if( lpSessDesc->u2.lpszPasswordA )
3325 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3328 else /* UNICODE */
3330 if( lpSessDesc->u1.lpszSessionName )
3332 dwSize += sizeof( WCHAR ) *
3333 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3336 if( lpSessDesc->u2.lpszPassword )
3338 dwSize += sizeof( WCHAR ) *
3339 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3343 return dwSize;
3346 /* Assumes that contugous buffers are already allocated. */
3347 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3348 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3350 BYTE* lpStartOfFreeSpace;
3352 if( lpSessionDest == NULL )
3354 ERR( "NULL lpSessionDest\n" );
3355 return;
3358 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3360 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3362 if( bAnsi )
3364 if( lpSessionSrc->u1.lpszSessionNameA )
3366 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3367 lpSessionDest->u1.lpszSessionNameA );
3368 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3369 lpStartOfFreeSpace +=
3370 lstrlenA( (LPSTR)lpSessionDest->u1.lpszSessionNameA ) + 1;
3373 if( lpSessionSrc->u2.lpszPasswordA )
3375 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3376 lpSessionDest->u2.lpszPasswordA );
3377 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3378 lpStartOfFreeSpace +=
3379 lstrlenA( (LPSTR)lpSessionDest->u2.lpszPasswordA ) + 1;
3382 else /* UNICODE */
3384 if( lpSessionSrc->u1.lpszSessionName )
3386 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3387 lpSessionDest->u1.lpszSessionName );
3388 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3389 lpStartOfFreeSpace += sizeof(WCHAR) *
3390 ( lstrlenW( (LPWSTR)lpSessionDest->u1.lpszSessionName ) + 1 );
3393 if( lpSessionSrc->u2.lpszPassword )
3395 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3396 lpSessionDest->u2.lpszPassword );
3397 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3398 lpStartOfFreeSpace += sizeof(WCHAR) *
3399 ( lstrlenW( (LPWSTR)lpSessionDest->u2.lpszPassword ) + 1 );
3405 static HRESULT WINAPI DP_IF_AddGroupToGroup
3406 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3408 lpGroupData lpGParentData;
3409 lpGroupData lpGData;
3410 lpGroupList lpNewGList;
3412 TRACE( "(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
3414 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3416 return DPERR_INVALIDGROUP;
3419 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3421 return DPERR_INVALIDGROUP;
3424 /* Create a player list (ie "shortcut" ) */
3425 lpNewGList = (lpGroupList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3426 sizeof( *lpNewGList ) );
3427 if( lpNewGList == NULL )
3429 return DPERR_CANTADDPLAYER;
3432 /* Add the shortcut */
3433 lpGData->uRef++;
3434 lpNewGList->lpGData = lpGData;
3436 /* Add the player to the list of players for this group */
3437 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3439 /* Send a ADDGROUPTOGROUP message */
3440 FIXME( "Not sending message\n" );
3442 return DP_OK;
3445 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3446 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3448 ICOM_THIS(IDirectPlay3Impl,iface);
3449 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3452 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3453 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3455 ICOM_THIS(IDirectPlay3Impl,iface);
3456 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3459 static HRESULT WINAPI DP_IF_CreateGroupInGroup
3460 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3461 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3462 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3464 lpGroupData lpGParentData;
3465 lpGroupList lpGList;
3466 lpGroupData lpGData;
3468 TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
3469 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3470 dwDataSize, dwFlags, bAnsi );
3472 /* Verify that the specified parent is valid */
3473 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3474 idParentGroup ) ) == NULL
3477 return DPERR_INVALIDGROUP;
3480 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3481 dwFlags, idParentGroup, bAnsi );
3483 if( lpGData == NULL )
3485 return DPERR_CANTADDPLAYER; /* yes player not group */
3488 /* Something else is referencing this data */
3489 lpGData->uRef++;
3491 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3493 /* The list has now been inserted into the interface group list. We now
3494 need to put a "shortcut" to this group in the parent group */
3495 lpGList = (lpGroupList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3496 sizeof( *lpGList ) );
3497 if( lpGList == NULL )
3499 FIXME( "Memory leak\n" );
3500 return DPERR_CANTADDPLAYER; /* yes player not group */
3503 lpGList->lpGData = lpGData;
3505 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3507 /* Let the SP know that we've created this group */
3508 if( This->dp2->spData.lpCB->CreateGroup )
3510 DPSP_CREATEGROUPDATA data;
3512 TRACE( "Calling SP CreateGroup\n" );
3514 data.idGroup = *lpidGroup;
3515 data.dwFlags = dwFlags;
3516 data.lpSPMessageHeader = lpMsgHdr;
3517 data.lpISP = This->dp2->spData.lpISP;
3519 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3522 /* Inform all other peers of the creation of a new group. If there are
3523 * no peers keep this quiet.
3525 if( This->dp2->lpSessionDesc &&
3526 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3528 DPMSG_CREATEPLAYERORGROUP msg;
3530 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3531 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3532 msg.dpId = *lpidGroup;
3533 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3534 msg.lpData = lpData;
3535 msg.dwDataSize = dwDataSize;
3536 msg.dpnName = *lpGroupName;
3538 /* FIXME: Correct to just use send effectively? */
3539 /* FIXME: Should size include data w/ message or just message "header" */
3540 /* FIXME: Check return code */
3541 DP_SendEx( (IDirectPlay2Impl*)This,
3542 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3543 0, 0, NULL, NULL, bAnsi );
3546 return DP_OK;
3549 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3550 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3551 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3552 DWORD dwFlags )
3554 ICOM_THIS(IDirectPlay3Impl,iface);
3556 *lpidGroup = DPID_UNKNOWN;
3558 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3559 lpGroupName, lpData, dwDataSize, dwFlags,
3560 TRUE );
3563 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3564 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3565 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3566 DWORD dwFlags )
3568 ICOM_THIS(IDirectPlay3Impl,iface);
3570 *lpidGroup = DPID_UNKNOWN;
3572 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3573 lpGroupName, lpData, dwDataSize,
3574 dwFlags, FALSE );
3577 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
3578 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3580 lpGroupList lpGList;
3581 lpGroupData lpGParentData;
3583 TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
3585 /* Is the parent group valid? */
3586 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3588 return DPERR_INVALIDGROUP;
3591 /* Remove the group from the parent group queue */
3592 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3594 if( lpGList == NULL )
3596 return DPERR_INVALIDGROUP;
3599 /* Decrement the ref count */
3600 lpGList->lpGData->uRef--;
3602 /* Free up the list item */
3603 HeapFree( GetProcessHeap(), 0, lpGList );
3605 /* Should send a DELETEGROUPFROMGROUP message */
3606 FIXME( "message not sent\n" );
3608 return DP_OK;
3611 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3612 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3614 ICOM_THIS(IDirectPlay3Impl,iface);
3615 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3618 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3619 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3621 ICOM_THIS(IDirectPlay3Impl,iface);
3622 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3625 static
3626 BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3627 LPDWORD lpdwBufSize )
3629 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3630 HRESULT hr;
3632 dpCompoundAddress.dwDataSize = sizeof( GUID );
3633 memcpy( &dpCompoundAddress.guidDataType, &DPAID_ServiceProvider,
3634 sizeof( GUID ) ) ;
3635 dpCompoundAddress.lpData = lpcSpGuid;
3637 *lplpAddrBuf = NULL;
3638 *lpdwBufSize = 0;
3640 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3641 lpdwBufSize, TRUE );
3643 if( hr != DPERR_BUFFERTOOSMALL )
3645 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3646 return FALSE;
3649 /* Now allocate the buffer */
3650 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3651 *lpdwBufSize );
3653 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3654 lpdwBufSize, TRUE );
3655 if( FAILED(hr) )
3657 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3658 return FALSE;
3661 return TRUE;
3664 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
3665 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3667 ICOM_THIS(IDirectPlay3Impl,iface);
3668 TRACE("(%p)->(%p,%p,%p,0x%08lx)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3670 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3671 if( dwFlags == 0 )
3673 dwFlags = DPCONNECTION_DIRECTPLAY;
3676 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3677 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3680 return DPERR_INVALIDFLAGS;
3683 if( !lpEnumCallback || !*lpEnumCallback )
3685 return DPERR_INVALIDPARAMS;
3688 /* Enumerate DirectPlay service providers */
3689 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3691 HKEY hkResult;
3692 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3693 LPCSTR guidDataSubKey = "Guid";
3694 char subKeyName[51];
3695 DWORD dwIndex, sizeOfSubKeyName=50;
3696 FILETIME filetime;
3698 /* Need to loop over the service providers in the registry */
3699 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3700 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3702 /* Hmmm. Does this mean that there are no service providers? */
3703 ERR(": no service providers?\n");
3704 return DP_OK;
3708 /* Traverse all the service providers we have available */
3709 for( dwIndex=0;
3710 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3711 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3712 ++dwIndex, sizeOfSubKeyName=51 )
3715 HKEY hkServiceProvider;
3716 GUID serviceProviderGUID;
3717 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3718 char returnBuffer[51];
3719 WCHAR buff[51];
3720 DPNAME dpName;
3721 BOOL bBuildPass;
3723 LPVOID lpAddressBuffer = NULL;
3724 DWORD dwAddressBufferSize = 0;
3726 TRACE(" this time through: %s\n", subKeyName );
3728 /* Get a handle for this particular service provider */
3729 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3730 &hkServiceProvider ) != ERROR_SUCCESS )
3732 ERR(": what the heck is going on?\n" );
3733 continue;
3736 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3737 NULL, &returnTypeGUID, returnBuffer,
3738 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3740 ERR(": missing GUID registry data members\n" );
3741 continue;
3744 /* FIXME: Check return types to ensure we're interpreting data right */
3745 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3746 CLSIDFromString( buff, &serviceProviderGUID );
3747 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3749 /* Fill in the DPNAME struct for the service provider */
3750 dpName.dwSize = sizeof( dpName );
3751 dpName.dwFlags = 0;
3752 dpName.u1.lpszShortNameA = subKeyName;
3753 dpName.u2.lpszLongNameA = NULL;
3755 /* Create the compound address for the service provider.
3756 * NOTE: This is a gruesome architectural scar right now. DP
3757 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3758 * native dll just gets around this little bit by allocating an
3759 * 80 byte buffer which isn't even filled with a valid compound
3760 * address. Oh well. Creating a proper compound address is the
3761 * way to go anyways despite this method taking slightly more
3762 * heap space and realtime :) */
3764 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3765 &lpAddressBuffer,
3766 &dwAddressBufferSize );
3767 if( !bBuildPass )
3769 ERR( "Can't build compound addr\n" );
3770 return DPERR_GENERIC;
3773 /* The enumeration will return FALSE if we are not to continue */
3774 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3775 &dpName, DPCONNECTION_DIRECTPLAY, lpContext ) )
3777 return DP_OK;
3782 /* Enumerate DirectPlayLobby service providers */
3783 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3785 HKEY hkResult;
3786 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3787 LPCSTR guidDataSubKey = "Guid";
3788 char subKeyName[51];
3789 DWORD dwIndex, sizeOfSubKeyName=50;
3790 FILETIME filetime;
3792 /* Need to loop over the service providers in the registry */
3793 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3794 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3796 /* Hmmm. Does this mean that there are no service providers? */
3797 ERR(": no service providers?\n");
3798 return DP_OK;
3802 /* Traverse all the lobby providers we have available */
3803 for( dwIndex=0;
3804 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3805 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3806 ++dwIndex, sizeOfSubKeyName=51 )
3809 HKEY hkServiceProvider;
3810 GUID serviceProviderGUID;
3811 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3812 char returnBuffer[51];
3813 WCHAR buff[51];
3814 DPNAME dpName;
3815 HRESULT hr;
3817 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3818 LPVOID lpAddressBuffer = NULL;
3819 DWORD dwAddressBufferSize = 0;
3821 TRACE(" this time through: %s\n", subKeyName );
3823 /* Get a handle for this particular service provider */
3824 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3825 &hkServiceProvider ) != ERROR_SUCCESS )
3827 ERR(": what the heck is going on?\n" );
3828 continue;
3831 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3832 NULL, &returnTypeGUID, returnBuffer,
3833 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3835 ERR(": missing GUID registry data members\n" );
3836 continue;
3839 /* FIXME: Check return types to ensure we're interpreting data right */
3840 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3841 CLSIDFromString( buff, &serviceProviderGUID );
3842 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3844 /* Fill in the DPNAME struct for the service provider */
3845 dpName.dwSize = sizeof( dpName );
3846 dpName.dwFlags = 0;
3847 dpName.u1.lpszShortNameA = subKeyName;
3848 dpName.u2.lpszLongNameA = NULL;
3850 /* Create the compound address for the service provider.
3851 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3852 nast stuff. This may be why the native dll just gets around this little bit by
3853 allocating an 80 byte buffer which isn't even a filled with a valid compound
3854 address. Oh well. Creating a proper compound address is the way to go anyways
3855 despite this method taking slightly more heap space and realtime :) */
3857 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3858 dpCompoundAddress.dwDataSize = sizeof( GUID );
3859 dpCompoundAddress.lpData = &serviceProviderGUID;
3861 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3862 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3864 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3865 return hr;
3868 /* Now allocate the buffer */
3869 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3871 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3872 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3874 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3875 return hr;
3878 /* The enumeration will return FALSE if we are not to continue */
3879 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3880 &dpName, DPCONNECTION_DIRECTPLAYLOBBY, lpContext ) )
3882 return DP_OK;
3887 return DP_OK;
3890 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3891 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3893 ICOM_THIS(IDirectPlay3Impl,iface);
3894 FIXME("(%p)->(%p,%p,%p,0x%08lx): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3895 return DP_OK;
3898 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
3899 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3900 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3901 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3903 lpGroupList lpGList;
3904 lpGroupData lpGData;
3906 FIXME( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n",
3907 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3908 lpContext, dwFlags, bAnsi );
3910 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3912 return DPERR_INVALIDGROUP;
3915 if( DPQ_IS_EMPTY( lpGData->groups ) )
3917 return DP_OK;
3920 lpGList = DPQ_FIRST( lpGData->groups );
3922 for( ;; )
3924 /* FIXME: Should check dwFlags for match here */
3926 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3927 &lpGList->lpGData->name, dwFlags,
3928 lpContext ) )
3930 return DP_OK; /* User requested break */
3933 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3935 break;
3938 lpGList = DPQ_NEXT( lpGList->groups );
3942 return DP_OK;
3945 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
3946 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3947 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3948 DWORD dwFlags )
3950 ICOM_THIS(IDirectPlay3Impl,iface);
3951 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3952 lpEnumPlayersCallback2, lpContext, dwFlags,
3953 TRUE );
3956 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3957 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3958 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3959 DWORD dwFlags )
3961 ICOM_THIS(IDirectPlay3Impl,iface);
3962 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3963 lpEnumPlayersCallback2, lpContext, dwFlags,
3964 FALSE );
3967 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
3968 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3970 ICOM_THIS(IDirectPlay3Impl,iface);
3971 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3972 return DP_OK;
3975 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
3976 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3978 ICOM_THIS(IDirectPlay3Impl,iface);
3979 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3980 return DP_OK;
3983 BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
3984 REFGUID guidDataType,
3985 DWORD dwDataSize,
3986 LPCVOID lpData,
3987 LPVOID lpContext )
3989 /* Looking for the GUID of the provider to load */
3990 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
3991 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
3994 TRACE( "Found SP/LP (%s) %s (data size = 0x%08lx)\n",
3995 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
3997 if( dwDataSize != sizeof( GUID ) )
3999 ERR( "Invalid sp/lp guid size 0x%08lx\n", dwDataSize );
4002 memcpy( lpContext, lpData, dwDataSize );
4004 /* There shouldn't be more than 1 GUID/compound address */
4005 return FALSE;
4008 /* Still waiting for what we want */
4009 return TRUE;
4013 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4014 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4016 UINT i;
4017 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4018 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4019 LPCSTR guidDataSubKey = "Guid";
4020 LPCSTR majVerDataSubKey = "dwReserved1";
4021 LPCSTR minVerDataSubKey = "dwReserved2";
4022 LPCSTR pathSubKey = "Path";
4024 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4026 /* FIXME: Cloned code with a quick hack. */
4027 for( i=0; i<2; i++ )
4029 HKEY hkResult;
4030 LPCSTR searchSubKey;
4031 char subKeyName[51];
4032 DWORD dwIndex, sizeOfSubKeyName=50;
4033 FILETIME filetime;
4035 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4036 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4039 /* Need to loop over the service providers in the registry */
4040 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4041 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4043 /* Hmmm. Does this mean that there are no service providers? */
4044 ERR(": no service providers?\n");
4045 return 0;
4048 /* Traverse all the service providers we have available */
4049 for( dwIndex=0;
4050 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4051 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4052 ++dwIndex, sizeOfSubKeyName=51 )
4055 HKEY hkServiceProvider;
4056 GUID serviceProviderGUID;
4057 DWORD returnType, sizeOfReturnBuffer = 255;
4058 char returnBuffer[256];
4059 WCHAR buff[51];
4060 DWORD dwTemp, len;
4062 TRACE(" this time through: %s\n", subKeyName );
4064 /* Get a handle for this particular service provider */
4065 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4066 &hkServiceProvider ) != ERROR_SUCCESS )
4068 ERR(": what the heck is going on?\n" );
4069 continue;
4072 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4073 NULL, &returnType, returnBuffer,
4074 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4076 ERR(": missing GUID registry data members\n" );
4077 continue;
4080 /* FIXME: Check return types to ensure we're interpreting data right */
4081 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4082 CLSIDFromString( buff, &serviceProviderGUID );
4083 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4085 /* Determine if this is the Service Provider that the user asked for */
4086 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4088 continue;
4091 if( i == 0 ) /* DP SP */
4093 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4094 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4095 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4098 sizeOfReturnBuffer = 255;
4100 /* Get dwReserved1 */
4101 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4102 NULL, &returnType, returnBuffer,
4103 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4105 ERR(": missing dwReserved1 registry data members\n") ;
4106 continue;
4109 if( i == 0 )
4110 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4112 sizeOfReturnBuffer = 255;
4114 /* Get dwReserved2 */
4115 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4116 NULL, &returnType, returnBuffer,
4117 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4119 ERR(": missing dwReserved1 registry data members\n") ;
4120 continue;
4123 if( i == 0 )
4124 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4126 sizeOfReturnBuffer = 255;
4128 /* Get the path for this service provider */
4129 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4130 NULL, NULL, returnBuffer,
4131 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4133 ERR(": missing PATH registry data members: 0x%08lx\n", dwTemp );
4134 continue;
4137 TRACE( "Loading %s\n", returnBuffer );
4138 return LoadLibraryA( returnBuffer );
4142 return 0;
4145 static
4146 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4148 HRESULT hr;
4149 LPDPSP_SPINIT SPInit;
4151 /* Initialize the service provider by calling SPInit */
4152 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4154 if( SPInit == NULL )
4156 ERR( "Service provider doesn't provide SPInit interface?\n" );
4157 FreeLibrary( hServiceProvider );
4158 return DPERR_UNAVAILABLE;
4161 TRACE( "Calling SPInit (DP SP entry point)\n" );
4163 hr = (*SPInit)( &This->dp2->spData );
4165 if( FAILED(hr) )
4167 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4168 FreeLibrary( hServiceProvider );
4169 return hr;
4172 /* FIXME: Need to verify the sanity of the returned callback table
4173 * using IsBadCodePtr */
4174 This->dp2->bSPInitialized = TRUE;
4176 /* This interface is now initialized as a DP object */
4177 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4179 /* Store the handle of the module so that we can unload it later */
4180 This->dp2->hServiceProvider = hServiceProvider;
4182 return hr;
4185 static
4186 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4188 HRESULT hr;
4189 LPSP_INIT DPLSPInit;
4191 /* Initialize the service provider by calling SPInit */
4192 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4194 if( DPLSPInit == NULL )
4196 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4197 FreeLibrary( hLobbyProvider );
4198 return DPERR_UNAVAILABLE;
4201 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4203 hr = (*DPLSPInit)( &This->dp2->dplspData );
4205 if( FAILED(hr) )
4207 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4208 FreeLibrary( hLobbyProvider );
4209 return hr;
4212 /* FIXME: Need to verify the sanity of the returned callback table
4213 * using IsBadCodePtr */
4215 This->dp2->bDPLSPInitialized = TRUE;
4217 /* This interface is now initialized as a lobby object */
4218 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4220 /* Store the handle of the module so that we can unload it later */
4221 This->dp2->hDPLobbyProvider = hLobbyProvider;
4223 return hr;
4226 static HRESULT WINAPI DP_IF_InitializeConnection
4227 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4229 HMODULE hServiceProvider;
4230 HRESULT hr;
4231 GUID guidSP;
4232 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4233 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4235 TRACE("(%p)->(%p,0x%08lx,%u)\n", This, lpConnection, dwFlags, bAnsi );
4237 if( dwFlags != 0 )
4239 return DPERR_INVALIDFLAGS;
4242 /* Find out what the requested SP is and how large this buffer is */
4243 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4244 dwAddrSize, &guidSP );
4246 if( FAILED(hr) )
4248 ERR( "Invalid compound address?\n" );
4249 return DPERR_UNAVAILABLE;
4252 /* Load the service provider */
4253 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4255 if( hServiceProvider == 0 )
4257 ERR( "Unable to load service provider\n" );
4258 return DPERR_UNAVAILABLE;
4261 if( bIsDpSp )
4263 /* Fill in what we can of the Service Provider required information.
4264 * The rest was be done in DP_LoadSP
4266 This->dp2->spData.lpAddress = lpConnection;
4267 This->dp2->spData.dwAddressSize = dwAddrSize;
4268 This->dp2->spData.lpGuid = &guidSP;
4270 hr = DP_InitializeDPSP( This, hServiceProvider );
4272 else
4274 This->dp2->dplspData.lpAddress = lpConnection;
4276 hr = DP_InitializeDPLSP( This, hServiceProvider );
4279 if( FAILED(hr) )
4281 return hr;
4284 return DP_OK;
4287 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4288 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4290 ICOM_THIS(IDirectPlay3Impl,iface);
4292 /* This may not be externally invoked once either an SP or LP is initialized */
4293 if( This->dp2->connectionInitialized != NO_PROVIDER )
4295 return DPERR_ALREADYINITIALIZED;
4298 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4301 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4302 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4304 ICOM_THIS(IDirectPlay3Impl,iface);
4306 /* This may not be externally invoked once either an SP or LP is initialized */
4307 if( This->dp2->connectionInitialized != NO_PROVIDER )
4309 return DPERR_ALREADYINITIALIZED;
4312 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4315 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4316 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4317 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4319 ICOM_THIS(IDirectPlay2Impl,iface); /* Yes a dp 2 interface */
4320 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4323 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4324 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4325 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4327 ICOM_THIS(IDirectPlay2Impl,iface); /* Yes a dp 2 interface */
4328 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4331 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4332 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4334 ICOM_THIS(IDirectPlay3Impl,iface);
4335 FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4336 return DP_OK;
4339 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4340 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4342 ICOM_THIS(IDirectPlay3Impl,iface);
4343 FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4344 return DP_OK;
4347 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4348 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4350 ICOM_THIS(IDirectPlay3Impl,iface);
4351 FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4352 return DP_OK;
4355 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4356 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4358 ICOM_THIS(IDirectPlay3Impl,iface);
4359 FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4360 return DP_OK;
4363 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4364 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4366 ICOM_THIS(IDirectPlay3Impl,iface);
4367 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup );
4368 return DP_OK;
4371 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4372 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4374 ICOM_THIS(IDirectPlay3Impl,iface);
4375 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup );
4376 return DP_OK;
4379 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4380 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4382 ICOM_THIS(IDirectPlay3Impl,iface);
4383 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags );
4384 return DP_OK;
4387 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4388 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4390 ICOM_THIS(IDirectPlay3Impl,iface);
4391 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags );
4392 return DP_OK;
4395 static HRESULT WINAPI DP_IF_GetGroupParent
4396 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4397 BOOL bAnsi )
4399 lpGroupData lpGData;
4401 TRACE("(%p)->(0x%08lx,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4403 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4405 return DPERR_INVALIDGROUP;
4408 *lpidGroup = lpGData->dpid;
4410 return DP_OK;
4413 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4414 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4416 ICOM_THIS(IDirectPlay3Impl,iface);
4417 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4419 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4420 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4422 ICOM_THIS(IDirectPlay3Impl,iface);
4423 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4426 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4427 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4429 ICOM_THIS(IDirectPlay3Impl,iface);
4430 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4431 return DP_OK;
4434 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4435 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4437 ICOM_THIS(IDirectPlay3Impl,iface);
4438 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4439 return DP_OK;
4442 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4443 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4445 ICOM_THIS(IDirectPlay3Impl,iface);
4446 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags );
4447 return DP_OK;
4450 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4451 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4453 ICOM_THIS(IDirectPlay3Impl,iface);
4454 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags );
4455 return DP_OK;
4458 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4459 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4461 ICOM_THIS(IDirectPlay4Impl,iface);
4462 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner );
4463 return DP_OK;
4466 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4467 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4469 ICOM_THIS(IDirectPlay4Impl,iface);
4470 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner );
4471 return DP_OK;
4474 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4475 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4477 ICOM_THIS(IDirectPlay4Impl,iface);
4478 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner );
4479 return DP_OK;
4482 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4483 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4485 ICOM_THIS(IDirectPlay4Impl,iface);
4486 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner );
4487 return DP_OK;
4490 static HRESULT WINAPI DP_SendEx
4491 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4492 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4493 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4495 lpPlayerList lpPList;
4496 lpGroupData lpGData;
4497 BOOL bValidDestination = FALSE;
4499 FIXME( "(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx,0x%08lx,0x%08lx,%p,%p,%u)"
4500 ": stub\n",
4501 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4502 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4504 /* FIXME: Add parameter checking */
4505 /* FIXME: First call to this needs to aquire a message id which will be
4506 * used for multiple sends
4509 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4511 /* Verify that the message is being sent from a valid local player. The
4512 * from player may be anonymous DPID_UNKNOWN
4514 if( idFrom != DPID_UNKNOWN )
4516 if( ( lpPList = DP_FindPlayer( This, idFrom ) ) == NULL )
4518 WARN( "INFO: Invalid from player 0x%08lx\n", idFrom );
4519 return DPERR_INVALIDPLAYER;
4523 /* Verify that the message is being sent to a valid player, group or to
4524 * everyone. If it's valid, send it to those players.
4526 if( idTo == DPID_ALLPLAYERS )
4528 bValidDestination = TRUE;
4530 /* See if SP has the ability to multicast. If so, use it */
4531 if( This->dp2->spData.lpCB->SendToGroupEx )
4533 FIXME( "Use group sendex to group 0\n" );
4535 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4537 FIXME( "Use obsolete group send to group 0\n" );
4539 else /* No multicast, multiplicate */
4541 /* Send to all players we know about */
4542 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4546 if( ( !bValidDestination ) &&
4547 ( DP_FindPlayer( This, idTo ) != NULL )
4550 bValidDestination = TRUE;
4552 /* Have the service provider send this message */
4553 /* FIXME: Could optimize for local interface sends */
4554 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4555 dwTimeout, lpContext, lpdwMsgID );
4558 if( ( !bValidDestination ) &&
4559 ( ( lpGData = DP_FindAnyGroup( This, idTo ) ) != NULL )
4562 bValidDestination = TRUE;
4564 /* See if SP has the ability to multicast. If so, use it */
4565 if( This->dp2->spData.lpCB->SendToGroupEx )
4567 FIXME( "Use group sendex\n" );
4569 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4571 FIXME( "Use obsolete group send to group\n" );
4573 else /* No multicast, multiplicate */
4575 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4578 #if 0
4579 if( bExpectReply )
4581 DWORD dwWaitReturn;
4583 This->dp2->hReplyEvent = CreateEventA( NULL, FALSE, FALSE, NULL );
4585 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4586 if( dwWaitReturn != WAIT_OBJECT_0 )
4588 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4591 #endif
4594 if( !bValidDestination )
4596 return DPERR_INVALIDPLAYER;
4598 else
4600 /* FIXME: Should return what the send returned */
4601 return DP_OK;
4606 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4607 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4608 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4609 LPVOID lpContext, LPDWORD lpdwMsgID )
4611 ICOM_THIS(IDirectPlay2Impl,iface); /* yes downcast to 2 */
4612 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4613 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4616 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4617 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4618 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4619 LPVOID lpContext, LPDWORD lpdwMsgID )
4621 ICOM_THIS(IDirectPlay2Impl,iface); /* yes downcast to 2 */
4622 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4623 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4626 static HRESULT WINAPI DP_SP_SendEx
4627 ( IDirectPlay2Impl* This, DWORD dwFlags,
4628 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4629 LPVOID lpContext, LPDWORD lpdwMsgID )
4631 LPDPMSG lpMElem;
4633 FIXME( ": stub\n" );
4635 /* FIXME: This queuing should only be for async messages */
4637 lpMElem = (LPDPMSG)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4638 sizeof( *lpMElem ) );
4639 lpMElem->msg = (DPMSG_GENERIC*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4640 dwDataSize );
4642 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4644 /* FIXME: Need to queue based on priority */
4645 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4647 return DP_OK;
4650 static HRESULT WINAPI DP_IF_GetMessageQueue
4651 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4652 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4654 HRESULT hr = DP_OK;
4656 FIXME( "(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,%p,%u): semi stub\n",
4657 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4659 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4660 /* FIXME: What about sends which are not immediate? */
4662 if( This->dp2->spData.lpCB->GetMessageQueue )
4664 DPSP_GETMESSAGEQUEUEDATA data;
4666 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4668 /* FIXME: None of this is documented :( */
4670 data.lpISP = This->dp2->spData.lpISP;
4671 data.dwFlags = dwFlags;
4672 data.idFrom = idFrom;
4673 data.idTo = idTo;
4674 data.lpdwNumMsgs = lpdwNumMsgs;
4675 data.lpdwNumBytes = lpdwNumBytes;
4677 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4679 else
4681 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4684 return hr;
4687 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4688 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4689 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4691 ICOM_THIS(IDirectPlay4Impl,iface);
4692 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4693 lpdwNumBytes, TRUE );
4696 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4697 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4698 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4700 ICOM_THIS(IDirectPlay4Impl,iface);
4701 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4702 lpdwNumBytes, FALSE );
4705 static HRESULT WINAPI DP_IF_CancelMessage
4706 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4707 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4709 HRESULT hr = DP_OK;
4711 FIXME( "(%p)->(0x%08lx,0x%08lx,%u): semi stub\n",
4712 This, dwMsgID, dwFlags, bAnsi );
4714 if( This->dp2->spData.lpCB->Cancel )
4716 DPSP_CANCELDATA data;
4718 TRACE( "Calling SP Cancel\n" );
4720 /* FIXME: Undocumented callback */
4722 data.lpISP = This->dp2->spData.lpISP;
4723 data.dwFlags = dwFlags;
4724 data.lprglpvSPMsgID = NULL;
4725 data.cSPMsgID = dwMsgID;
4726 data.dwMinPriority = dwMinPriority;
4727 data.dwMaxPriority = dwMaxPriority;
4729 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4731 else
4733 FIXME( "SP doesn't implement Cancel\n" );
4736 return hr;
4739 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4740 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4742 ICOM_THIS(IDirectPlay4Impl,iface);
4744 if( dwFlags != 0 )
4746 return DPERR_INVALIDFLAGS;
4749 if( dwMsgID == 0 )
4751 dwFlags |= DPCANCELSEND_ALL;
4754 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4757 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4758 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4760 ICOM_THIS(IDirectPlay4Impl,iface);
4762 if( dwFlags != 0 )
4764 return DPERR_INVALIDFLAGS;
4767 if( dwMsgID == 0 )
4769 dwFlags |= DPCANCELSEND_ALL;
4772 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4775 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4776 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4777 DWORD dwFlags )
4779 ICOM_THIS(IDirectPlay4Impl,iface);
4781 if( dwFlags != 0 )
4783 return DPERR_INVALIDFLAGS;
4786 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4787 dwMaxPriority, TRUE );
4790 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4791 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4792 DWORD dwFlags )
4794 ICOM_THIS(IDirectPlay4Impl,iface);
4796 if( dwFlags != 0 )
4798 return DPERR_INVALIDFLAGS;
4801 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4802 dwMaxPriority, FALSE );
4805 /* Note: Hack so we can reuse the old functions without compiler warnings */
4806 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4807 # define XCAST(fun) (typeof(directPlay2WVT.fun))
4808 #else
4809 # define XCAST(fun) (void*)
4810 #endif
4812 static ICOM_VTABLE(IDirectPlay2) directPlay2WVT =
4814 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4815 XCAST(QueryInterface)DP_QueryInterface,
4816 XCAST(AddRef)DP_AddRef,
4817 XCAST(Release)DP_Release,
4819 DirectPlay2WImpl_AddPlayerToGroup,
4820 DirectPlay2WImpl_Close,
4821 DirectPlay2WImpl_CreateGroup,
4822 DirectPlay2WImpl_CreatePlayer,
4823 DirectPlay2WImpl_DeletePlayerFromGroup,
4824 DirectPlay2WImpl_DestroyGroup,
4825 DirectPlay2WImpl_DestroyPlayer,
4826 DirectPlay2WImpl_EnumGroupPlayers,
4827 DirectPlay2WImpl_EnumGroups,
4828 DirectPlay2WImpl_EnumPlayers,
4829 DirectPlay2WImpl_EnumSessions,
4830 DirectPlay2WImpl_GetCaps,
4831 DirectPlay2WImpl_GetGroupData,
4832 DirectPlay2WImpl_GetGroupName,
4833 DirectPlay2WImpl_GetMessageCount,
4834 DirectPlay2WImpl_GetPlayerAddress,
4835 DirectPlay2WImpl_GetPlayerCaps,
4836 DirectPlay2WImpl_GetPlayerData,
4837 DirectPlay2WImpl_GetPlayerName,
4838 DirectPlay2WImpl_GetSessionDesc,
4839 DirectPlay2WImpl_Initialize,
4840 DirectPlay2WImpl_Open,
4841 DirectPlay2WImpl_Receive,
4842 DirectPlay2WImpl_Send,
4843 DirectPlay2WImpl_SetGroupData,
4844 DirectPlay2WImpl_SetGroupName,
4845 DirectPlay2WImpl_SetPlayerData,
4846 DirectPlay2WImpl_SetPlayerName,
4847 DirectPlay2WImpl_SetSessionDesc
4849 #undef XCAST
4851 /* Note: Hack so we can reuse the old functions without compiler warnings */
4852 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4853 # define XCAST(fun) (typeof(directPlay2AVT.fun))
4854 #else
4855 # define XCAST(fun) (void*)
4856 #endif
4858 static ICOM_VTABLE(IDirectPlay2) directPlay2AVT =
4860 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4861 XCAST(QueryInterface)DP_QueryInterface,
4862 XCAST(AddRef)DP_AddRef,
4863 XCAST(Release)DP_Release,
4865 DirectPlay2AImpl_AddPlayerToGroup,
4866 DirectPlay2AImpl_Close,
4867 DirectPlay2AImpl_CreateGroup,
4868 DirectPlay2AImpl_CreatePlayer,
4869 DirectPlay2AImpl_DeletePlayerFromGroup,
4870 DirectPlay2AImpl_DestroyGroup,
4871 DirectPlay2AImpl_DestroyPlayer,
4872 DirectPlay2AImpl_EnumGroupPlayers,
4873 DirectPlay2AImpl_EnumGroups,
4874 DirectPlay2AImpl_EnumPlayers,
4875 DirectPlay2AImpl_EnumSessions,
4876 DirectPlay2AImpl_GetCaps,
4877 DirectPlay2AImpl_GetGroupData,
4878 DirectPlay2AImpl_GetGroupName,
4879 DirectPlay2AImpl_GetMessageCount,
4880 DirectPlay2AImpl_GetPlayerAddress,
4881 DirectPlay2AImpl_GetPlayerCaps,
4882 DirectPlay2AImpl_GetPlayerData,
4883 DirectPlay2AImpl_GetPlayerName,
4884 DirectPlay2AImpl_GetSessionDesc,
4885 DirectPlay2AImpl_Initialize,
4886 DirectPlay2AImpl_Open,
4887 DirectPlay2AImpl_Receive,
4888 DirectPlay2AImpl_Send,
4889 DirectPlay2AImpl_SetGroupData,
4890 DirectPlay2AImpl_SetGroupName,
4891 DirectPlay2AImpl_SetPlayerData,
4892 DirectPlay2AImpl_SetPlayerName,
4893 DirectPlay2AImpl_SetSessionDesc
4895 #undef XCAST
4898 /* Note: Hack so we can reuse the old functions without compiler warnings */
4899 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4900 # define XCAST(fun) (typeof(directPlay3AVT.fun))
4901 #else
4902 # define XCAST(fun) (void*)
4903 #endif
4905 static ICOM_VTABLE(IDirectPlay3) directPlay3AVT =
4907 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4908 XCAST(QueryInterface)DP_QueryInterface,
4909 XCAST(AddRef)DP_AddRef,
4910 XCAST(Release)DP_Release,
4912 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
4913 XCAST(Close)DirectPlay2AImpl_Close,
4914 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
4915 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
4916 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
4917 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
4918 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
4919 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
4920 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
4921 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
4922 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
4923 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
4924 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
4925 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
4926 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
4927 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
4928 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
4929 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
4930 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
4931 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
4932 XCAST(Initialize)DirectPlay2AImpl_Initialize,
4933 XCAST(Open)DirectPlay2AImpl_Open,
4934 XCAST(Receive)DirectPlay2AImpl_Receive,
4935 XCAST(Send)DirectPlay2AImpl_Send,
4936 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
4937 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
4938 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
4939 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
4940 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
4942 DirectPlay3AImpl_AddGroupToGroup,
4943 DirectPlay3AImpl_CreateGroupInGroup,
4944 DirectPlay3AImpl_DeleteGroupFromGroup,
4945 DirectPlay3AImpl_EnumConnections,
4946 DirectPlay3AImpl_EnumGroupsInGroup,
4947 DirectPlay3AImpl_GetGroupConnectionSettings,
4948 DirectPlay3AImpl_InitializeConnection,
4949 DirectPlay3AImpl_SecureOpen,
4950 DirectPlay3AImpl_SendChatMessage,
4951 DirectPlay3AImpl_SetGroupConnectionSettings,
4952 DirectPlay3AImpl_StartSession,
4953 DirectPlay3AImpl_GetGroupFlags,
4954 DirectPlay3AImpl_GetGroupParent,
4955 DirectPlay3AImpl_GetPlayerAccount,
4956 DirectPlay3AImpl_GetPlayerFlags
4958 #undef XCAST
4960 /* Note: Hack so we can reuse the old functions without compiler warnings */
4961 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4962 # define XCAST(fun) (typeof(directPlay3WVT.fun))
4963 #else
4964 # define XCAST(fun) (void*)
4965 #endif
4966 static ICOM_VTABLE(IDirectPlay3) directPlay3WVT =
4968 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4969 XCAST(QueryInterface)DP_QueryInterface,
4970 XCAST(AddRef)DP_AddRef,
4971 XCAST(Release)DP_Release,
4973 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
4974 XCAST(Close)DirectPlay2WImpl_Close,
4975 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
4976 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
4977 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
4978 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
4979 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
4980 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
4981 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
4982 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
4983 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
4984 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
4985 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
4986 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
4987 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
4988 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
4989 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
4990 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
4991 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
4992 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
4993 XCAST(Initialize)DirectPlay2WImpl_Initialize,
4994 XCAST(Open)DirectPlay2WImpl_Open,
4995 XCAST(Receive)DirectPlay2WImpl_Receive,
4996 XCAST(Send)DirectPlay2WImpl_Send,
4997 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
4998 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
4999 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5000 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5001 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5003 DirectPlay3WImpl_AddGroupToGroup,
5004 DirectPlay3WImpl_CreateGroupInGroup,
5005 DirectPlay3WImpl_DeleteGroupFromGroup,
5006 DirectPlay3WImpl_EnumConnections,
5007 DirectPlay3WImpl_EnumGroupsInGroup,
5008 DirectPlay3WImpl_GetGroupConnectionSettings,
5009 DirectPlay3WImpl_InitializeConnection,
5010 DirectPlay3WImpl_SecureOpen,
5011 DirectPlay3WImpl_SendChatMessage,
5012 DirectPlay3WImpl_SetGroupConnectionSettings,
5013 DirectPlay3WImpl_StartSession,
5014 DirectPlay3WImpl_GetGroupFlags,
5015 DirectPlay3WImpl_GetGroupParent,
5016 DirectPlay3WImpl_GetPlayerAccount,
5017 DirectPlay3WImpl_GetPlayerFlags
5019 #undef XCAST
5021 /* Note: Hack so we can reuse the old functions without compiler warnings */
5022 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5023 # define XCAST(fun) (typeof(directPlay4WVT.fun))
5024 #else
5025 # define XCAST(fun) (void*)
5026 #endif
5027 static ICOM_VTABLE(IDirectPlay4) directPlay4WVT =
5029 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
5030 XCAST(QueryInterface)DP_QueryInterface,
5031 XCAST(AddRef)DP_AddRef,
5032 XCAST(Release)DP_Release,
5034 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5035 XCAST(Close)DirectPlay2WImpl_Close,
5036 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5037 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5038 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5039 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5040 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5041 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5042 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5043 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5044 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5045 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5046 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5047 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5048 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5049 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5050 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5051 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5052 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5053 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5054 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5055 XCAST(Open)DirectPlay2WImpl_Open,
5056 XCAST(Receive)DirectPlay2WImpl_Receive,
5057 XCAST(Send)DirectPlay2WImpl_Send,
5058 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5059 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5060 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5061 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5062 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5064 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5065 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5066 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5067 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5068 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5069 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5070 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5071 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5072 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5073 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5074 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5075 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5076 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5077 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5078 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5080 DirectPlay4WImpl_GetGroupOwner,
5081 DirectPlay4WImpl_SetGroupOwner,
5082 DirectPlay4WImpl_SendEx,
5083 DirectPlay4WImpl_GetMessageQueue,
5084 DirectPlay4WImpl_CancelMessage,
5085 DirectPlay4WImpl_CancelPriority
5087 #undef XCAST
5090 /* Note: Hack so we can reuse the old functions without compiler warnings */
5091 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5092 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5093 #else
5094 # define XCAST(fun) (void*)
5095 #endif
5096 static ICOM_VTABLE(IDirectPlay4) directPlay4AVT =
5098 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
5099 XCAST(QueryInterface)DP_QueryInterface,
5100 XCAST(AddRef)DP_AddRef,
5101 XCAST(Release)DP_Release,
5103 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5104 XCAST(Close)DirectPlay2AImpl_Close,
5105 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5106 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5107 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5108 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5109 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5110 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5111 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5112 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5113 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5114 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5115 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5116 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5117 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5118 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5119 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5120 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5121 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5122 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5123 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5124 XCAST(Open)DirectPlay2AImpl_Open,
5125 XCAST(Receive)DirectPlay2AImpl_Receive,
5126 XCAST(Send)DirectPlay2AImpl_Send,
5127 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5128 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5129 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5130 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5131 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5133 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5134 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5135 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5136 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5137 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5138 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5139 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5140 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5141 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5142 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5143 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5144 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5145 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5146 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5147 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5149 DirectPlay4AImpl_GetGroupOwner,
5150 DirectPlay4AImpl_SetGroupOwner,
5151 DirectPlay4AImpl_SendEx,
5152 DirectPlay4AImpl_GetMessageQueue,
5153 DirectPlay4AImpl_CancelMessage,
5154 DirectPlay4AImpl_CancelPriority
5156 #undef XCAST
5158 extern
5159 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5160 DPID idPlayer,
5161 LPVOID* lplpData )
5163 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5165 if( lpPlayer == NULL )
5167 return DPERR_INVALIDPLAYER;
5170 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5172 return DP_OK;
5175 extern
5176 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5177 DPID idPlayer,
5178 LPVOID lpData )
5180 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5182 if( lpPlayer == NULL )
5184 return DPERR_INVALIDPLAYER;
5187 lpPlayer->lpPData->lpSPPlayerData = lpData;
5189 return DP_OK;
5192 /***************************************************************************
5193 * DirectPlayEnumerate [DPLAYX.9]
5194 * DirectPlayEnumerateA [DPLAYX.2]
5196 * The pointer to the structure lpContext will be filled with the
5197 * appropriate data for each service offered by the OS. These services are
5198 * not necessarily available on this particular machine but are defined
5199 * as simple service providers under the "Service Providers" registry key.
5200 * This structure is then passed to lpEnumCallback for each of the different
5201 * services.
5203 * This API is useful only for applications written using DirectX3 or
5204 * worse. It is superseded by IDirectPlay3::EnumConnections which also
5205 * gives information on the actual connections.
5207 * defn of a service provider:
5208 * A dynamic-link library used by DirectPlay to communicate over a network.
5209 * The service provider contains all the network-specific code required
5210 * to send and receive messages. Online services and network operators can
5211 * supply service providers to use specialized hardware, protocols, communications
5212 * media, and network resources.
5214 * TODO: Allocate string buffer space from the heap (length from reg)
5215 * Pass real device driver numbers...
5216 * Get the GUID properly...
5218 HRESULT WINAPI DirectPlayEnumerateA( LPDPENUMDPCALLBACKA lpEnumCallback,
5219 LPVOID lpContext )
5222 HKEY hkResult;
5223 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
5224 DWORD dwIndex;
5225 DWORD sizeOfSubKeyName=50;
5226 char subKeyName[51];
5227 FILETIME filetime;
5229 TRACE(": lpEnumCallback=%p lpContext=%p\n", lpEnumCallback, lpContext );
5231 if( !lpEnumCallback || !*lpEnumCallback )
5233 return DPERR_INVALIDPARAMS;
5236 /* Need to loop over the service providers in the registry */
5237 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
5238 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
5240 /* Hmmm. Does this mean that there are no service providers? */
5241 ERR(": no service providers?\n");
5242 return DPERR_NOSERVICEPROVIDER;
5245 /* Traverse all the service providers we have available */
5246 for( dwIndex=0;
5247 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5248 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
5249 ++dwIndex, sizeOfSubKeyName=50 )
5251 LPCSTR majVerDataSubKey = "dwReserved1";
5252 LPCSTR minVerDataSubKey = "dwReserved2";
5253 LPCSTR guidDataSubKey = "Guid";
5254 HKEY hkServiceProvider;
5255 GUID serviceProviderGUID;
5256 DWORD returnTypeGUID, returnTypeReserved, sizeOfReturnBuffer = 50;
5257 char returnBuffer[51];
5258 WCHAR buff[51];
5259 DWORD majVersionNum , minVersionNum = 0;
5261 TRACE(" this time through: %s\n", subKeyName );
5263 /* Get a handle for this particular service provider */
5264 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
5265 &hkServiceProvider ) != ERROR_SUCCESS )
5267 ERR(": what the heck is going on?\n" );
5268 continue;
5271 /* Get the GUID, Device major number and device minor number
5272 * from the registry.
5274 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
5275 NULL, &returnTypeGUID, returnBuffer,
5276 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
5278 ERR(": missing GUID registry data members\n" );
5279 continue;
5282 /* FIXME: Check return types to ensure we're interpreting data right */
5283 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
5284 CLSIDFromString( buff, &serviceProviderGUID );
5286 /* FIXME: Need to know which of dwReserved1 and dwReserved2 are maj and min */
5288 sizeOfReturnBuffer = 50;
5289 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
5290 NULL, &returnTypeReserved, returnBuffer,
5291 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
5293 ERR(": missing dwReserved1 registry data members\n") ;
5294 continue;
5296 memcpy( &majVersionNum, returnBuffer, sizeof(majVersionNum) );
5298 sizeOfReturnBuffer = 50;
5299 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
5300 NULL, &returnTypeReserved, returnBuffer,
5301 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
5303 ERR(": missing dwReserved2 registry data members\n") ;
5304 continue;
5306 memcpy( &minVersionNum, returnBuffer, sizeof(minVersionNum) );
5309 /* The enumeration will return FALSE if we are not to continue */
5310 if( !lpEnumCallback( &serviceProviderGUID , subKeyName,
5311 majVersionNum, minVersionNum, lpContext ) )
5313 WARN("lpEnumCallback returning FALSE\n" );
5314 break;
5318 return DP_OK;
5322 /***************************************************************************
5323 * DirectPlayEnumerateW [DPLAYX.3]
5326 HRESULT WINAPI DirectPlayEnumerateW( LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5329 FIXME(":stub\n");
5331 return DPERR_OUTOFMEMORY;
5335 typedef struct tagCreateEnum
5337 LPVOID lpConn;
5338 LPCGUID lpGuid;
5339 } CreateEnumData, *lpCreateEnumData;
5341 /* Find and copy the matching connection for the SP guid */
5342 static BOOL CALLBACK cbDPCreateEnumConnections(
5343 LPCGUID lpguidSP,
5344 LPVOID lpConnection,
5345 DWORD dwConnectionSize,
5346 LPCDPNAME lpName,
5347 DWORD dwFlags,
5348 LPVOID lpContext)
5350 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5352 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5354 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5356 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5357 dwConnectionSize );
5358 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5360 /* Found the record that we were looking for */
5361 return FALSE;
5364 /* Haven't found what were looking for yet */
5365 return TRUE;
5369 /***************************************************************************
5370 * DirectPlayCreate [DPLAYX.1]
5373 HRESULT WINAPI DirectPlayCreate
5374 ( LPGUID lpGUID, LPDIRECTPLAY2 *lplpDP, IUnknown *pUnk)
5376 HRESULT hr;
5377 LPDIRECTPLAY3A lpDP3A;
5378 CreateEnumData cbData;
5380 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5382 if( pUnk != NULL )
5384 return CLASS_E_NOAGGREGATION;
5387 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5388 give them an IDirectPlay2A object and hope that doesn't cause problems */
5389 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5391 return DPERR_UNAVAILABLE;
5394 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5396 /* The GUID_NULL means don't bind a service provider. Just return the
5397 interface as is */
5398 return DP_OK;
5401 /* Bind the desired service provider since lpGUID is non NULL */
5402 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5404 /* We're going to use a DP3 interface */
5405 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5406 (LPVOID*)&lpDP3A );
5407 if( FAILED(hr) )
5409 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5410 return hr;
5413 cbData.lpConn = NULL;
5414 cbData.lpGuid = lpGUID;
5416 /* We were given a service provider, find info about it... */
5417 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5418 &cbData, DPCONNECTION_DIRECTPLAY );
5419 if( ( FAILED(hr) ) ||
5420 ( cbData.lpConn == NULL )
5423 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5424 IDirectPlayX_Release( lpDP3A );
5425 return DPERR_UNAVAILABLE;
5428 /* Initialize the service provider */
5429 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5430 if( FAILED(hr) )
5432 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5433 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5434 IDirectPlayX_Release( lpDP3A );
5435 return hr;
5438 /* Release our version of the interface now that we're done with it */
5439 IDirectPlayX_Release( lpDP3A );
5440 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5442 return DP_OK;