- Implement:
[wine.git] / dlls / dplayx / dplay.c
blob7bf65829c2093454700f900d15c83cafccab6200
1 /* Direct Play 2,3,4 Implementation
3 * Copyright 1998,1999,2000,2001 - Peter Hunnisett
5 * <presently under construction - contact hunnise@nortelnetworks.com>
7 */
9 #include "wine/port.h"
11 #include <string.h>
13 #include "windef.h"
14 #include "winerror.h"
15 #include "winbase.h"
16 #include "winnt.h"
17 #include "winreg.h"
18 #include "winnls.h"
19 #include "wine/unicode.h"
20 #include "dplay.h"
21 #include "debugtools.h"
23 #include "dpinit.h"
24 #include "dplayx_global.h"
25 #include "name_server.h"
26 #include "dplayx_queue.h"
27 #include "dplaysp.h"
28 #include "dplay_global.h"
30 DEFAULT_DEBUG_CHANNEL(dplay);
32 /* FIXME: Should this be externed? */
33 extern HRESULT DPL_CreateCompoundAddress
34 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
35 LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
38 /* Local function prototypes */
39 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
40 static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
41 LPDPNAME lpName, DWORD dwFlags,
42 HANDLE hEvent, BOOL bAnsi );
43 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi );
44 static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
45 LPVOID lpData, DWORD dwDataSize );
47 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, LPDPID lpid,
48 LPDPNAME lpName, DWORD dwFlags,
49 DPID idParent, BOOL bAnsi );
50 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
51 LPVOID lpData, DWORD dwDataSize );
52 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
53 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
54 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
55 DWORD dwPlayerType,
56 LPCDPNAME lpName,
57 DWORD dwFlags,
58 LPVOID lpContext );
59 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
60 static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
61 LPCDPNAME lpName, DWORD dwFlags,
62 LPVOID lpContext );
63 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
65 /* Helper methods for player/group interfaces */
66 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
67 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
68 DPID idPlayer, BOOL bAnsi );
69 static HRESULT WINAPI DP_IF_CreatePlayer
70 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
71 LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
72 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
73 static HRESULT WINAPI DP_IF_DestroyGroup
74 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
75 static HRESULT WINAPI DP_IF_DestroyPlayer
76 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
77 static HRESULT WINAPI DP_IF_EnumGroupPlayers
78 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
79 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
80 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
81 static HRESULT WINAPI DP_IF_EnumGroups
82 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
83 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
84 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
85 static HRESULT WINAPI DP_IF_EnumPlayers
86 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
87 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
88 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
89 static HRESULT WINAPI DP_IF_GetGroupData
90 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
91 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
92 static HRESULT WINAPI DP_IF_GetGroupName
93 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
94 LPDWORD lpdwDataSize, BOOL bAnsi );
95 static HRESULT WINAPI DP_IF_GetPlayerData
96 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
97 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
98 static HRESULT WINAPI DP_IF_GetPlayerName
99 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
100 LPDWORD lpdwDataSize, BOOL bAnsi );
101 static HRESULT WINAPI DP_IF_SetGroupName
102 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
103 DWORD dwFlags, BOOL bAnsi );
104 static HRESULT WINAPI DP_IF_SetPlayerData
105 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
106 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
107 static HRESULT WINAPI DP_IF_SetPlayerName
108 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
109 DWORD dwFlags, BOOL bAnsi );
110 static HRESULT WINAPI DP_IF_AddGroupToGroup
111 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
112 static HRESULT WINAPI DP_IF_CreateGroup
113 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
114 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
115 DWORD dwFlags, BOOL bAnsi );
116 static HRESULT WINAPI DP_IF_CreateGroupInGroup
117 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
118 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
119 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
120 static HRESULT WINAPI DP_IF_AddPlayerToGroup
121 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
122 DPID idPlayer, BOOL bAnsi );
123 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
124 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
125 static HRESULT WINAPI DP_SetSessionDesc
126 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
127 DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
128 static HRESULT WINAPI DP_SecureOpen
129 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
130 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
131 BOOL bAnsi );
132 static HRESULT WINAPI DP_SendEx
133 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
134 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
135 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
136 static HRESULT WINAPI DP_IF_Receive
137 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
138 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
139 static HRESULT WINAPI DP_IF_GetMessageQueue
140 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
141 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
142 static HRESULT WINAPI DP_SP_SendEx
143 ( IDirectPlay2Impl* This, DWORD dwFlags,
144 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
145 LPVOID lpContext, LPDWORD lpdwMsgID );
146 static HRESULT WINAPI DP_IF_SetGroupData
147 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
148 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
149 static HRESULT WINAPI DP_IF_GetPlayerCaps
150 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
151 DWORD dwFlags );
152 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
153 static HRESULT WINAPI DP_IF_CancelMessage
154 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
155 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
156 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
157 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
158 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
159 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
160 static HRESULT WINAPI DP_IF_GetGroupParent
161 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
162 BOOL bAnsi );
163 static HRESULT WINAPI DP_IF_GetCaps
164 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
165 static HRESULT WINAPI DP_IF_EnumSessions
166 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
167 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
168 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
169 static HRESULT WINAPI DP_IF_InitializeConnection
170 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
171 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
172 LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
173 DWORD dwFlags, LPVOID lpContext );
174 static BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
175 LPDWORD lpdwBufSize );
179 static inline DPID DP_NextObjectId(void);
180 static DPID DP_GetRemoteNextObjectId(void);
183 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
184 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
187 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
188 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
189 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
196 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
197 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
198 we don't have to change much */
199 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
201 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
202 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
204 /* Strip out all dwFlags values for CREATEPLAYER msg */
205 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
207 static DWORD kludgePlayerGroupId = 1000;
209 /* ------------------------------------------------------------------ */
212 static BOOL DP_CreateIUnknown( LPVOID lpDP )
214 ICOM_THIS(IDirectPlay2AImpl,lpDP);
216 This->unk = (DirectPlayIUnknownData*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
217 sizeof( *(This->unk) ) );
218 if ( This->unk == NULL )
220 return FALSE;
223 InitializeCriticalSection( &This->unk->DP_lock );
225 return TRUE;
228 static BOOL DP_DestroyIUnknown( LPVOID lpDP )
230 ICOM_THIS(IDirectPlay2AImpl,lpDP);
232 DeleteCriticalSection( &This->unk->DP_lock );
233 HeapFree( GetProcessHeap(), 0, This->unk );
235 return TRUE;
238 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
240 ICOM_THIS(IDirectPlay2AImpl,lpDP);
242 This->dp2 = (DirectPlay2Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
243 sizeof( *(This->dp2) ) );
244 if ( This->dp2 == NULL )
246 return FALSE;
249 This->dp2->bConnectionOpen = FALSE;
251 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
253 This->dp2->bHostInterface = FALSE;
255 DPQ_INIT(This->dp2->receiveMsgs);
256 DPQ_INIT(This->dp2->sendMsgs);
257 DPQ_INIT(This->dp2->replysExpected);
259 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
261 /* FIXME: Memory leak */
262 return FALSE;
265 /* Provide an initial session desc with nothing in it */
266 This->dp2->lpSessionDesc = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(),
267 HEAP_ZERO_MEMORY,
268 sizeof( *This->dp2->lpSessionDesc ) );
269 if( This->dp2->lpSessionDesc == NULL )
271 /* FIXME: Memory leak */
272 return FALSE;
274 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
276 /* We are a emulating a dp 6 implementation */
277 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
279 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
280 sizeof( *This->dp2->spData.lpCB ) );
281 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
282 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
284 /* This is the pointer to the service provider */
285 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
286 (LPVOID*)&This->dp2->spData.lpISP, This ) )
289 /* FIXME: Memory leak */
290 return FALSE;
293 /* Setup lobby provider information */
294 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
295 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
296 sizeof( *This->dp2->dplspData.lpCB ) );
297 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
299 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
300 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
303 /* FIXME: Memory leak */
304 return FALSE;
307 return TRUE;
310 /* Definition of the global function in dplayx_queue.h. #
311 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
312 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
314 HeapFree( GetProcessHeap(), 0, elem );
317 /* Function to delete the list of groups with this interface. Needs to
318 * delete the group and player lists associated with this group as well
319 * as the group data associated with this group. It should not delete
320 * player data as that is shared with the top player list and will be
321 * deleted with that.
323 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList );
324 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList )
326 DPQ_DELETEQ( elem->lpGData->groups, groups,
327 lpGroupList, cbDeleteElemFromHeap );
328 DPQ_DELETEQ( elem->lpGData->players, players,
329 lpPlayerList, cbDeleteElemFromHeap );
330 HeapFree( GetProcessHeap(), 0, elem->lpGData );
331 HeapFree( GetProcessHeap(), 0, elem );
334 /* Function to delete the list of players with this interface. Needs to
335 * delete the player data for all players as well.
337 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList );
338 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList )
340 HeapFree( GetProcessHeap(), 0, elem->lpPData );
341 HeapFree( GetProcessHeap(), 0, elem );
344 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
346 ICOM_THIS(IDirectPlay2AImpl,lpDP);
348 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
350 TerminateThread( This->dp2->hEnumSessionThread, 0 );
351 CloseHandle( This->dp2->hEnumSessionThread );
354 /* Finish with the SP - have it shutdown */
355 if( This->dp2->spData.lpCB->ShutdownEx )
357 DPSP_SHUTDOWNDATA data;
359 TRACE( "Calling SP ShutdownEx\n" );
361 data.lpISP = This->dp2->spData.lpISP;
363 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
365 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
367 TRACE( "Calling obsolete SP Shutdown\n" );
368 (*This->dp2->spData.lpCB->Shutdown)();
371 /* Unload the SP (if it exists) */
372 if( This->dp2->hServiceProvider != 0 )
374 FreeLibrary( This->dp2->hServiceProvider );
377 /* Unload the Lobby Provider (if it exists) */
378 if( This->dp2->hDPLobbyProvider != 0 )
380 FreeLibrary( This->dp2->hDPLobbyProvider );
383 #if 0
384 DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
385 DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem );
386 #endif
388 /* FIXME: Need to delete receive and send msgs queue contents */
390 NS_DeleteSessionCache( This->dp2->lpNameServerData );
392 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
394 IDirectPlaySP_Release( This->dp2->spData.lpISP );
396 /* Delete the contents */
397 HeapFree( GetProcessHeap(), 0, This->dp2 );
399 return TRUE;
402 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
404 ICOM_THIS(IDirectPlay3AImpl,lpDP);
406 This->dp3 = (DirectPlay3Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
407 sizeof( *(This->dp3) ) );
408 if ( This->dp3 == NULL )
410 return FALSE;
413 return TRUE;
416 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
418 ICOM_THIS(IDirectPlay3AImpl,lpDP);
420 /* Delete the contents */
421 HeapFree( GetProcessHeap(), 0, This->dp3 );
423 return TRUE;
426 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
428 ICOM_THIS(IDirectPlay4AImpl,lpDP);
430 This->dp4 = (DirectPlay4Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
431 sizeof( *(This->dp4) ) );
432 if ( This->dp4 == NULL )
434 return FALSE;
437 return TRUE;
440 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
442 ICOM_THIS(IDirectPlay3AImpl,lpDP);
444 /* Delete the contents */
445 HeapFree( GetProcessHeap(), 0, This->dp4 );
447 return TRUE;
451 /* Create a new interface */
452 extern
453 HRESULT DP_CreateInterface
454 ( REFIID riid, LPVOID* ppvObj )
456 TRACE( " for %s\n", debugstr_guid( riid ) );
458 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
459 sizeof( IDirectPlay2Impl ) );
461 if( *ppvObj == NULL )
463 return DPERR_OUTOFMEMORY;
466 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
468 ICOM_THIS(IDirectPlay2Impl,*ppvObj);
469 ICOM_VTBL(This) = &directPlay2WVT;
471 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
473 ICOM_THIS(IDirectPlay2AImpl,*ppvObj);
474 ICOM_VTBL(This) = &directPlay2AVT;
476 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
478 ICOM_THIS(IDirectPlay3Impl,*ppvObj);
479 ICOM_VTBL(This) = &directPlay3WVT;
481 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
483 ICOM_THIS(IDirectPlay3AImpl,*ppvObj);
484 ICOM_VTBL(This) = &directPlay3AVT;
486 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
488 ICOM_THIS(IDirectPlay4Impl,*ppvObj);
489 ICOM_VTBL(This) = &directPlay4WVT;
491 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
493 ICOM_THIS(IDirectPlay4AImpl,*ppvObj);
494 ICOM_VTBL(This) = &directPlay4AVT;
496 else
498 /* Unsupported interface */
499 HeapFree( GetProcessHeap(), 0, *ppvObj );
500 *ppvObj = NULL;
502 return E_NOINTERFACE;
505 /* Initialize it */
506 if ( DP_CreateIUnknown( *ppvObj ) &&
507 DP_CreateDirectPlay2( *ppvObj ) &&
508 DP_CreateDirectPlay3( *ppvObj ) &&
509 DP_CreateDirectPlay4( *ppvObj )
512 IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
514 return S_OK;
517 /* Initialize failed, destroy it */
518 DP_DestroyDirectPlay4( *ppvObj );
519 DP_DestroyDirectPlay3( *ppvObj );
520 DP_DestroyDirectPlay2( *ppvObj );
521 DP_DestroyIUnknown( *ppvObj );
523 HeapFree( GetProcessHeap(), 0, *ppvObj );
525 *ppvObj = NULL;
526 return DPERR_NOMEMORY;
530 /* Direct Play methods */
532 /* Shared between all dplay types */
533 static HRESULT WINAPI DP_QueryInterface
534 ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
536 ICOM_THIS(IDirectPlay2Impl,iface);
537 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
539 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
540 sizeof( *This ) );
542 if( *ppvObj == NULL )
544 return DPERR_OUTOFMEMORY;
547 CopyMemory( *ppvObj, This, sizeof( *This ) );
548 (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
550 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
552 ICOM_THIS(IDirectPlay2Impl,*ppvObj);
553 ICOM_VTBL(This) = &directPlay2WVT;
555 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
557 ICOM_THIS(IDirectPlay2AImpl,*ppvObj);
558 ICOM_VTBL(This) = &directPlay2AVT;
560 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
562 ICOM_THIS(IDirectPlay3Impl,*ppvObj);
563 ICOM_VTBL(This) = &directPlay3WVT;
565 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
567 ICOM_THIS(IDirectPlay3AImpl,*ppvObj);
568 ICOM_VTBL(This) = &directPlay3AVT;
570 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
572 ICOM_THIS(IDirectPlay4Impl,*ppvObj);
573 ICOM_VTBL(This) = &directPlay4WVT;
575 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
577 ICOM_THIS(IDirectPlay4AImpl,*ppvObj);
578 ICOM_VTBL(This) = &directPlay4AVT;
580 else
582 /* Unsupported interface */
583 HeapFree( GetProcessHeap(), 0, *ppvObj );
584 *ppvObj = NULL;
586 return E_NOINTERFACE;
589 IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
591 return S_OK;
594 /* Shared between all dplay types */
595 static ULONG WINAPI DP_AddRef
596 ( LPDIRECTPLAY3 iface )
598 ULONG ulInterfaceRefCount, ulObjRefCount;
599 ICOM_THIS(IDirectPlay3Impl,iface);
601 ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
602 ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
604 TRACE( "ref count incremented to %lu:%lu for %p\n",
605 ulInterfaceRefCount, ulObjRefCount, This );
607 return ulObjRefCount;
610 static ULONG WINAPI DP_Release
611 ( LPDIRECTPLAY3 iface )
613 ULONG ulInterfaceRefCount, ulObjRefCount;
615 ICOM_THIS(IDirectPlay3Impl,iface);
617 ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
618 ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
620 TRACE( "ref count decremented to %lu:%lu for %p\n",
621 ulInterfaceRefCount, ulObjRefCount, This );
623 /* Deallocate if this is the last reference to the object */
624 if( ulObjRefCount == 0 )
626 /* If we're destroying the object, this must be the last ref
627 of the last interface */
628 DP_DestroyDirectPlay4( This );
629 DP_DestroyDirectPlay3( This );
630 DP_DestroyDirectPlay2( This );
631 DP_DestroyIUnknown( This );
634 /* Deallocate the interface */
635 if( ulInterfaceRefCount == 0 )
637 HeapFree( GetProcessHeap(), 0, This );
640 return ulObjRefCount;
643 static inline DPID DP_NextObjectId(void)
645 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
648 /* *lplpReply will be non NULL iff there is something to reply */
649 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
650 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
651 WORD wCommandId, WORD wVersion,
652 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
654 TRACE( "(%p)->(%p,0x%08lx,%p,%u,%u)\n",
655 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
656 wVersion );
658 switch( wCommandId )
660 /* Name server needs to handle this request */
661 case DPMSGCMD_ENUMSESSIONSREQUEST:
663 /* Reply expected */
664 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
666 break;
669 /* Name server needs to handle this request */
670 case DPMSGCMD_ENUMSESSIONSREPLY:
672 /* No reply expected */
673 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
674 This->dp2->spData.dwSPHeaderSize,
675 (LPDPMSG_ENUMSESSIONSREPLY)lpcMessageBody,
676 This->dp2->lpNameServerData );
677 break;
680 case DPMSGCMD_REQUESTNEWPLAYERID:
682 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg =
683 (LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody;
685 LPDPMSG_NEWPLAYERIDREPLY lpReply;
687 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
689 *lplpReply = (LPDPMSG_NEWPLAYERIDREPLY)HeapAlloc( GetProcessHeap(),
690 HEAP_ZERO_MEMORY,
691 *lpdwMsgSize );
693 FIXME( "Ignoring dwFlags 0x%08lx in request msg\n",
694 lpcMsg->dwFlags );
696 /* Setup the reply */
697 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
698 This->dp2->spData.dwSPHeaderSize );
700 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
701 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
702 lpReply->envelope.wVersion = DPMSGVER_DP6;
704 lpReply->dpidNewPlayerId = DP_NextObjectId();
706 TRACE( "Allocating new playerid 0x%08lx from remote request\n",
707 lpReply->dpidNewPlayerId );
709 break;
712 case DPMSGCMD_GETNAMETABLEREPLY:
713 case DPMSGCMD_NEWPLAYERIDREPLY:
716 #if 0
717 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
718 DebugBreak();
719 #endif
720 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
722 break;
725 #if 1
726 case DPMSGCMD_JUSTENVELOPE:
728 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08lx\n", lpcMessageHeader, ((LPDWORD)lpcMessageHeader)[1] );
729 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
730 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
732 #endif
734 case DPMSGCMD_FORWARDADDPLAYER:
736 #if 0
737 DebugBreak();
738 #endif
739 #if 1
740 TRACE( "Sending message to self to get my addr\n" );
741 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
742 #endif
743 break;
746 case DPMSGCMD_FORWARDADDPLAYERNACK:
748 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
749 break;
752 default:
754 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
755 DebugBreak();
756 break;
760 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
762 return DP_OK;
766 static HRESULT WINAPI DP_IF_AddPlayerToGroup
767 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
768 DPID idPlayer, BOOL bAnsi )
770 lpGroupData lpGData;
771 lpPlayerList lpPList;
772 lpPlayerList lpNewPList;
774 TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n",
775 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
777 /* Find the group */
778 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
780 return DPERR_INVALIDGROUP;
783 /* Find the player */
784 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
786 return DPERR_INVALIDPLAYER;
789 /* Create a player list (ie "shortcut" ) */
790 lpNewPList = (lpPlayerList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
791 sizeof( *lpNewPList ) );
792 if( lpNewPList == NULL )
794 return DPERR_CANTADDPLAYER;
797 /* Add the shortcut */
798 lpPList->lpPData->uRef++;
799 lpNewPList->lpPData = lpPList->lpPData;
801 /* Add the player to the list of players for this group */
802 DPQ_INSERT(lpGData->players,lpNewPList,players);
804 /* Let the SP know that we've added a player to the group */
805 if( This->dp2->spData.lpCB->AddPlayerToGroup )
807 DPSP_ADDPLAYERTOGROUPDATA data;
809 TRACE( "Calling SP AddPlayerToGroup\n" );
811 data.idPlayer = idPlayer;
812 data.idGroup = idGroup;
813 data.lpISP = This->dp2->spData.lpISP;
815 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
818 /* Inform all other peers of the addition of player to the group. If there are
819 * no peers keep this event quiet.
820 * Also, if this event was the result of another machine sending it to us,
821 * don't bother rebroadcasting it.
823 if( ( lpMsgHdr == NULL ) &&
824 This->dp2->lpSessionDesc &&
825 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
827 DPMSG_ADDPLAYERTOGROUP msg;
828 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
830 msg.dpIdGroup = idGroup;
831 msg.dpIdPlayer = idPlayer;
833 /* FIXME: Correct to just use send effectively? */
834 /* FIXME: Should size include data w/ message or just message "header" */
835 /* FIXME: Check return code */
836 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
839 return DP_OK;
842 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
843 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
845 ICOM_THIS(IDirectPlay2Impl,iface);
846 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
849 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
850 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
852 ICOM_THIS(IDirectPlay2Impl,iface);
853 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
856 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
858 HRESULT hr = DP_OK;
860 TRACE("(%p)->(%u)\n", This, bAnsi );
862 /* FIXME: Need to find a new host I assume (how?) */
863 /* FIXME: Need to destroy all local groups */
864 /* FIXME: Need to migrate all remotely visible players to the new host */
866 /* Invoke the SP callback to inform of session close */
867 if( This->dp2->spData.lpCB->CloseEx )
869 DPSP_CLOSEDATA data;
871 TRACE( "Calling SP CloseEx\n" );
873 data.lpISP = This->dp2->spData.lpISP;
875 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
878 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
880 TRACE( "Calling SP Close (obsolete interface)\n" );
882 hr = (*This->dp2->spData.lpCB->Close)();
885 return hr;
888 static HRESULT WINAPI DirectPlay2AImpl_Close
889 ( LPDIRECTPLAY2A iface )
891 ICOM_THIS(IDirectPlay2Impl,iface);
892 return DP_IF_Close( This, TRUE );
895 static HRESULT WINAPI DirectPlay2WImpl_Close
896 ( LPDIRECTPLAY2 iface )
898 ICOM_THIS(IDirectPlay2Impl,iface);
899 return DP_IF_Close( This, FALSE );
902 static
903 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, LPDPID lpid,
904 LPDPNAME lpName, DWORD dwFlags,
905 DPID idParent, BOOL bAnsi )
907 lpGroupData lpGData;
909 /* Allocate the new space and add to end of high level group list */
910 lpGData = (lpGroupData) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
911 sizeof( *lpGData ) );
913 if( lpGData == NULL )
915 return NULL;
918 DPQ_INIT(lpGData->groups);
919 DPQ_INIT(lpGData->players);
921 /* Set the desired player ID - no sanity checking to see if it exists */
922 lpGData->dpid = *lpid;
924 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
926 /* FIXME: Should we check that the parent exists? */
927 lpGData->parent = idParent;
929 /* FIXME: Should we validate the dwFlags? */
930 lpGData->dwFlags = dwFlags;
932 TRACE( "Created group id 0x%08lx\n", *lpid );
934 return lpGData;
937 /* This method assumes that all links to it are already deleted */
938 static void
939 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
941 lpGroupList lpGList;
943 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
945 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
947 if( lpGList == NULL )
949 ERR( "DPID 0x%08lx not found\n", dpid );
950 return;
953 if( --(lpGList->lpGData->uRef) )
955 FIXME( "Why is this not the last reference to group?\n" );
956 DebugBreak();
959 /* Delete player */
960 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
961 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
963 /* Remove and Delete Player List object */
964 HeapFree( GetProcessHeap(), 0, lpGList );
968 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
970 lpGroupList lpGroups;
972 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
974 if( dpid == DPID_SYSTEM_GROUP )
976 return This->dp2->lpSysGroup;
978 else
980 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
983 if( lpGroups == NULL )
985 return NULL;
988 return lpGroups->lpGData;
991 static HRESULT WINAPI DP_IF_CreateGroup
992 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
993 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
994 DWORD dwFlags, BOOL bAnsi )
996 lpGroupData lpGData;
998 TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
999 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
1000 dwFlags, bAnsi );
1002 /* If the name is not specified, we must provide one */
1003 if( DPID_UNKNOWN == *lpidGroup )
1005 /* If we are the name server, we decide on the group ids. If not, we
1006 * must ask for one before attempting a creation.
1008 if( This->dp2->bHostInterface )
1010 *lpidGroup = DP_NextObjectId();
1012 else
1014 *lpidGroup = DP_GetRemoteNextObjectId();
1018 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1019 DPID_NOPARENT_GROUP, bAnsi );
1021 if( lpGData == NULL )
1023 return DPERR_CANTADDPLAYER; /* yes player not group */
1026 if( DPID_SYSTEM_GROUP == *lpidGroup )
1028 This->dp2->lpSysGroup = lpGData;
1029 TRACE( "Inserting system group\n" );
1031 else
1033 /* Insert into the system group */
1034 lpGroupList lpGroup = (lpGroupList) HeapAlloc( GetProcessHeap(),
1035 HEAP_ZERO_MEMORY,
1036 sizeof( *lpGroup ) );
1037 lpGroup->lpGData = lpGData;
1039 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1042 /* Something is now referencing this data */
1043 lpGData->uRef++;
1045 /* Set all the important stuff for the group */
1046 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1048 /* FIXME: We should only create the system group if GetCaps returns
1049 * DPCAPS_GROUPOPTIMIZED.
1052 /* Let the SP know that we've created this group */
1053 if( This->dp2->spData.lpCB->CreateGroup )
1055 DPSP_CREATEGROUPDATA data;
1056 DWORD dwCreateFlags = 0;
1058 TRACE( "Calling SP CreateGroup\n" );
1060 if( *lpidGroup == DPID_NOPARENT_GROUP )
1061 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1063 if( lpMsgHdr == NULL )
1064 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1066 if( dwFlags & DPGROUP_HIDDEN )
1067 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1069 data.idGroup = *lpidGroup;
1070 data.dwFlags = dwCreateFlags;
1071 data.lpSPMessageHeader = lpMsgHdr;
1072 data.lpISP = This->dp2->spData.lpISP;
1074 (*This->dp2->spData.lpCB->CreateGroup)( &data );
1077 /* Inform all other peers of the creation of a new group. If there are
1078 * no peers keep this event quiet.
1079 * Also if this message was sent to us, don't rebroadcast.
1081 if( ( lpMsgHdr == NULL ) &&
1082 This->dp2->lpSessionDesc &&
1083 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1085 DPMSG_CREATEPLAYERORGROUP msg;
1086 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1088 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
1089 msg.dpId = *lpidGroup;
1090 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1091 msg.lpData = lpData;
1092 msg.dwDataSize = dwDataSize;
1093 msg.dpnName = *lpGroupName;
1094 msg.dpIdParent = DPID_NOPARENT_GROUP;
1095 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1097 /* FIXME: Correct to just use send effectively? */
1098 /* FIXME: Should size include data w/ message or just message "header" */
1099 /* FIXME: Check return code */
1100 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
1101 0, 0, NULL, NULL, bAnsi );
1104 return DP_OK;
1107 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
1108 ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1109 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1111 *lpidGroup = DPID_UNKNOWN;
1113 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1114 lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
1117 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1118 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1119 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1121 *lpidGroup = DPID_UNKNOWN;
1123 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1124 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
1128 static void
1129 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1130 LPVOID lpData, DWORD dwDataSize )
1132 /* Clear out the data with this player */
1133 if( ( dwFlags & DPSET_LOCAL ) &&
1134 ( lpGData->dwLocalDataSize != 0 )
1137 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1138 lpGData->lpLocalData = NULL;
1139 lpGData->dwLocalDataSize = 0;
1141 if( ( dwFlags & DPSET_REMOTE ) &&
1142 ( lpGData->dwRemoteDataSize != 0 )
1145 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1146 lpGData->lpRemoteData = NULL;
1147 lpGData->dwRemoteDataSize = 0;
1150 /* Reallocate for new data */
1151 if( lpData != NULL )
1153 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1154 sizeof( dwDataSize ) );
1155 CopyMemory( lpNewData, lpData, dwDataSize );
1157 if( dwFlags & DPSET_REMOTE )
1159 lpGData->lpRemoteData = lpNewData;
1160 lpGData->dwRemoteDataSize = dwDataSize;
1163 if( dwFlags & DPSET_LOCAL )
1165 lpGData->lpLocalData = lpData;
1166 lpGData->dwLocalDataSize = dwDataSize;
1172 /* This function will just create the storage for the new player. */
1173 static
1174 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1175 LPDPNAME lpName, DWORD dwFlags,
1176 HANDLE hEvent, BOOL bAnsi )
1178 lpPlayerData lpPData;
1180 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1182 /* Allocate the storage for the player and associate it with list element */
1183 lpPData = (lpPlayerData) HeapAlloc( GetProcessHeap(),
1184 HEAP_ZERO_MEMORY,
1185 sizeof( *lpPData ) );
1186 if( lpPData == NULL )
1188 return NULL;
1191 /* Set the desired player ID */
1192 lpPData->dpid = *lpid;
1194 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1196 lpPData->dwFlags = dwFlags;
1198 /* If we were given an event handle, duplicate it */
1199 if( hEvent != 0 )
1201 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1202 GetCurrentProcess(), &lpPData->hEvent,
1203 0, FALSE, DUPLICATE_SAME_ACCESS )
1206 /* FIXME: Memory leak */
1207 ERR( "Can't duplicate player msg handle %x\n", hEvent );
1211 /* Initialize the SP data section */
1212 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1214 TRACE( "Created player id 0x%08lx\n", *lpid );
1216 return lpPData;
1219 /* Delete the contents of the DPNAME struct */
1220 static void
1221 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1223 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1224 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1227 /* This method assumes that all links to it are already deleted */
1228 static void
1229 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1231 lpPlayerList lpPList;
1233 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
1235 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1237 if( lpPList == NULL )
1239 ERR( "DPID 0x%08lx not found\n", dpid );
1240 return;
1243 /* Verify that this is the last reference to the data */
1244 if( --(lpPList->lpPData->uRef) )
1246 FIXME( "Why is this not the last reference to player?\n" );
1247 DebugBreak();
1250 /* Delete player */
1251 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1253 CloseHandle( lpPList->lpPData->hEvent );
1254 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1256 /* Delete Player List object */
1257 HeapFree( GetProcessHeap(), 0, lpPList );
1260 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1262 lpPlayerList lpPlayers;
1264 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
1266 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1268 return lpPlayers;
1271 /* Basic area for Dst must already be allocated */
1272 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi )
1274 if( lpSrc == NULL )
1276 ZeroMemory( lpDst, sizeof( *lpDst ) );
1277 lpDst->dwSize = sizeof( *lpDst );
1278 return TRUE;
1281 if( lpSrc->dwSize != sizeof( *lpSrc) )
1283 return FALSE;
1286 /* Delete any existing pointers */
1287 if( lpDst->u1.lpszShortNameA )
1289 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1292 if( lpDst->u2.lpszLongNameA )
1294 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1297 /* Copy as required */
1298 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1300 if( bAnsi )
1302 if( lpSrc->u1.lpszShortNameA )
1304 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1305 strlen(lpSrc->u1.lpszShortNameA)+1 );
1306 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1308 if( lpSrc->u2.lpszLongNameA )
1310 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1311 strlen(lpSrc->u2.lpszLongNameA)+1 );
1312 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1315 else
1317 if( lpSrc->u1.lpszShortNameA )
1319 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1320 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1321 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1323 if( lpSrc->u2.lpszLongNameA )
1325 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1326 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1327 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1331 return TRUE;
1334 static void
1335 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1336 LPVOID lpData, DWORD dwDataSize )
1338 /* Clear out the data with this player */
1339 if( ( dwFlags & DPSET_LOCAL ) &&
1340 ( lpPData->dwLocalDataSize != 0 )
1343 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1344 lpPData->lpLocalData = NULL;
1345 lpPData->dwLocalDataSize = 0;
1347 if( ( dwFlags & DPSET_REMOTE ) &&
1348 ( lpPData->dwRemoteDataSize != 0 )
1351 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1352 lpPData->lpRemoteData = NULL;
1353 lpPData->dwRemoteDataSize = 0;
1356 /* Reallocate for new data */
1357 if( lpData != NULL )
1359 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1360 sizeof( dwDataSize ) );
1361 CopyMemory( lpNewData, lpData, dwDataSize );
1363 if( dwFlags & DPSET_REMOTE )
1365 lpPData->lpRemoteData = lpNewData;
1366 lpPData->dwRemoteDataSize = dwDataSize;
1369 if( dwFlags & DPSET_LOCAL )
1371 lpPData->lpLocalData = lpData;
1372 lpPData->dwLocalDataSize = dwDataSize;
1378 static HRESULT WINAPI DP_IF_CreatePlayer
1379 ( IDirectPlay2Impl* This,
1380 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1381 LPDPID lpidPlayer,
1382 LPDPNAME lpPlayerName,
1383 HANDLE hEvent,
1384 LPVOID lpData,
1385 DWORD dwDataSize,
1386 DWORD dwFlags,
1387 BOOL bAnsi )
1389 HANDLE hr = DP_OK;
1390 lpPlayerData lpPData;
1391 lpPlayerList lpPList;
1392 DWORD dwCreateFlags = 0;
1394 TRACE( "(%p)->(%p,%p,%d,%p,0x%08lx,0x%08lx,%u)\n",
1395 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1396 dwDataSize, dwFlags, bAnsi );
1398 if( dwFlags == 0 )
1400 dwFlags = DPPLAYER_SPECTATOR;
1403 if( lpidPlayer == NULL )
1405 return DPERR_INVALIDPARAMS;
1409 /* Determine the creation flags for the player. These will be passed
1410 * to the name server if requesting a player id and to the SP when
1411 * informing it of the player creation
1414 if( dwFlags & DPPLAYER_SERVERPLAYER )
1416 if( *lpidPlayer == DPID_SERVERPLAYER )
1418 /* Server player for the host interface */
1419 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1421 else if( *lpidPlayer == DPID_NAME_SERVER )
1423 /* Name server - master of everything */
1424 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1426 else
1428 /* Server player for a non host interface */
1429 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1433 if( lpMsgHdr == NULL )
1434 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1437 /* Verify we know how to handle all the flags */
1438 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1439 ( dwFlags & DPPLAYER_SPECTATOR )
1443 /* Assume non fatal failure */
1444 ERR( "unknown dwFlags = 0x%08lx\n", dwFlags );
1447 /* If the name is not specified, we must provide one */
1448 if( *lpidPlayer == DPID_UNKNOWN )
1450 /* If we are the session master, we dish out the group/player ids */
1451 if( This->dp2->bHostInterface )
1453 *lpidPlayer = DP_NextObjectId();
1455 else
1457 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1459 if( FAILED(hr) )
1461 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1462 return hr;
1466 else
1468 /* FIXME: Would be nice to perhaps verify that we don't already have
1469 * this player.
1473 /* FIXME: Should we be storing these dwFlags or the creation ones? */
1474 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags,
1475 hEvent, bAnsi );
1477 if( lpPData == NULL )
1479 return DPERR_CANTADDPLAYER;
1482 /* Create the list object and link it in */
1483 lpPList = (lpPlayerList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1484 sizeof( *lpPList ) );
1485 if( lpPList == NULL )
1487 FIXME( "Memory leak\n" );
1488 return DPERR_CANTADDPLAYER;
1491 lpPData->uRef = 1;
1492 lpPList->lpPData = lpPData;
1494 /* Add the player to the system group */
1495 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1497 /* Update the information and send it to all players in the session */
1498 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1500 /* Let the SP know that we've created this player */
1501 if( This->dp2->spData.lpCB->CreatePlayer )
1503 DPSP_CREATEPLAYERDATA data;
1505 data.idPlayer = *lpidPlayer;
1506 data.dwFlags = dwCreateFlags;
1507 data.lpSPMessageHeader = lpMsgHdr;
1508 data.lpISP = This->dp2->spData.lpISP;
1510 TRACE( "Calling SP CreatePlayer 0x%08lx: dwFlags: 0x%08lx lpMsgHdr: %p\n",
1511 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1513 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1516 if( FAILED(hr) )
1518 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1519 return hr;
1522 /* Now let the SP know that this player is a member of the system group */
1523 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1525 DPSP_ADDPLAYERTOGROUPDATA data;
1527 data.idPlayer = *lpidPlayer;
1528 data.idGroup = DPID_SYSTEM_GROUP;
1529 data.lpISP = This->dp2->spData.lpISP;
1531 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1533 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1536 if( FAILED(hr) )
1538 ERR( "Failed to add player to sys group with sp: %s\n",
1539 DPLAYX_HresultToString(hr) );
1540 return hr;
1543 #if 1
1544 if( This->dp2->bHostInterface == FALSE )
1546 /* Let the name server know about the creation of this player */
1547 /* FIXME: Is this only to be done for the creation of a server player or
1548 * is this used for regular players? If only for server players, move
1549 * this call to DP_SecureOpen(...);
1551 #if 0
1552 TRACE( "Sending message to self to get my addr\n" );
1553 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1554 #endif
1556 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1558 #else
1559 /* Inform all other peers of the creation of a new player. If there are
1560 * no peers keep this quiet.
1561 * Also, if this was a remote event, no need to rebroadcast it.
1563 if( ( lpMsgHdr == NULL ) &&
1564 This->dp2->lpSessionDesc &&
1565 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1567 DPMSG_CREATEPLAYERORGROUP msg;
1568 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1570 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1571 msg.dpId = *lpidPlayer;
1572 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1573 msg.lpData = lpData;
1574 msg.dwDataSize = dwDataSize;
1575 msg.dpnName = *lpPlayerName;
1576 msg.dpIdParent = DPID_NOPARENT_GROUP;
1577 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1579 /* FIXME: Correct to just use send effectively? */
1580 /* FIXME: Should size include data w/ message or just message "header" */
1581 /* FIXME: Check return code */
1582 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1583 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1585 #endif
1587 return hr;
1590 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1591 ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1592 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1594 ICOM_THIS(IDirectPlay2Impl,iface);
1596 if( dwFlags & DPPLAYER_SERVERPLAYER )
1598 *lpidPlayer = DPID_SERVERPLAYER;
1600 else
1602 *lpidPlayer = DPID_UNKNOWN;
1605 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1606 lpData, dwDataSize, dwFlags, TRUE );
1609 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1610 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1611 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1613 ICOM_THIS(IDirectPlay2Impl,iface);
1615 if( dwFlags & DPPLAYER_SERVERPLAYER )
1617 *lpidPlayer = DPID_SERVERPLAYER;
1619 else
1621 *lpidPlayer = DPID_UNKNOWN;
1624 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1625 lpData, dwDataSize, dwFlags, FALSE );
1628 static DPID DP_GetRemoteNextObjectId(void)
1630 FIXME( ":stub\n" );
1632 /* Hack solution */
1633 return DP_NextObjectId();
1636 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
1637 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1638 DPID idPlayer, BOOL bAnsi )
1640 HRESULT hr = DP_OK;
1642 lpGroupData lpGData;
1643 lpPlayerList lpPList;
1645 TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n",
1646 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1648 /* Find the group */
1649 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1651 return DPERR_INVALIDGROUP;
1654 /* Find the player */
1655 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1657 return DPERR_INVALIDPLAYER;
1660 /* Remove the player shortcut from the group */
1661 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1663 if( lpPList == NULL )
1665 return DPERR_INVALIDPLAYER;
1668 /* One less reference */
1669 lpPList->lpPData->uRef--;
1671 /* Delete the Player List element */
1672 HeapFree( GetProcessHeap(), 0, lpPList );
1674 /* Inform the SP if they care */
1675 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1677 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1679 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1681 data.idPlayer = idPlayer;
1682 data.idGroup = idGroup;
1683 data.lpISP = This->dp2->spData.lpISP;
1685 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1688 /* Need to send a DELETEPLAYERFROMGROUP message */
1689 FIXME( "Need to send a message\n" );
1691 return hr;
1694 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1695 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1697 ICOM_THIS(IDirectPlay2Impl,iface);
1698 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1701 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1702 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1704 ICOM_THIS(IDirectPlay2Impl,iface);
1705 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1708 typedef struct _DPRGOPContext
1710 IDirectPlay3Impl* This;
1711 BOOL bAnsi;
1712 DPID idGroup;
1713 } DPRGOPContext, *lpDPRGOPContext;
1715 static BOOL CALLBACK
1716 cbRemoveGroupOrPlayer(
1717 DPID dpId,
1718 DWORD dwPlayerType,
1719 LPCDPNAME lpName,
1720 DWORD dwFlags,
1721 LPVOID lpContext )
1723 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1725 TRACE( "Removing element:0x%08lx (type:0x%08lx) from element:0x%08lx\n",
1726 dpId, dwPlayerType, lpCtxt->idGroup );
1728 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1730 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1731 dpId )
1735 ERR( "Unable to delete group 0x%08lx from group 0x%08lx\n",
1736 dpId, lpCtxt->idGroup );
1739 else
1741 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1742 NULL, lpCtxt->idGroup,
1743 dpId, lpCtxt->bAnsi )
1747 ERR( "Unable to delete player 0x%08lx from grp 0x%08lx\n",
1748 dpId, lpCtxt->idGroup );
1752 return TRUE; /* Continue enumeration */
1755 static HRESULT WINAPI DP_IF_DestroyGroup
1756 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1758 lpGroupData lpGData;
1759 DPRGOPContext context;
1761 FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n",
1762 This, lpMsgHdr, idGroup, bAnsi );
1764 /* Find the group */
1765 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1767 return DPERR_INVALIDPLAYER; /* yes player */
1770 context.This = (IDirectPlay3Impl*)This;
1771 context.bAnsi = bAnsi;
1772 context.idGroup = idGroup;
1774 /* Remove all players that this group has */
1775 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1776 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1778 /* Remove all links to groups that this group has since this is dp3 */
1779 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1780 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1782 /* Remove this group from the parent group - if it has one */
1783 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1784 ( lpGData->parent != DPID_SYSTEM_GROUP )
1787 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1788 idGroup );
1791 /* Now delete this group data and list from the system group */
1792 DP_DeleteGroup( This, idGroup );
1794 /* Let the SP know that we've destroyed this group */
1795 if( This->dp2->spData.lpCB->DeleteGroup )
1797 DPSP_DELETEGROUPDATA data;
1799 FIXME( "data.dwFlags is incorrect\n" );
1801 data.idGroup = idGroup;
1802 data.dwFlags = 0;
1803 data.lpISP = This->dp2->spData.lpISP;
1805 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1808 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1810 return DP_OK;
1813 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1814 ( LPDIRECTPLAY2A iface, DPID idGroup )
1816 ICOM_THIS(IDirectPlay2Impl,iface);
1817 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1820 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1821 ( LPDIRECTPLAY2 iface, DPID idGroup )
1823 ICOM_THIS(IDirectPlay2Impl,iface);
1824 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1827 typedef struct _DPFAGContext
1829 IDirectPlay2Impl* This;
1830 DPID idPlayer;
1831 BOOL bAnsi;
1832 } DPFAGContext, *lpDPFAGContext;
1834 static HRESULT WINAPI DP_IF_DestroyPlayer
1835 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1837 DPFAGContext cbContext;
1839 FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n",
1840 This, lpMsgHdr, idPlayer, bAnsi );
1842 if( DP_FindPlayer( This, idPlayer ) == NULL )
1844 return DPERR_INVALIDPLAYER;
1847 /* FIXME: If the player is remote, we must be the host to delete this */
1849 cbContext.This = This;
1850 cbContext.idPlayer = idPlayer;
1851 cbContext.bAnsi = bAnsi;
1853 /* Find each group and call DeletePlayerFromGroup if the player is a
1854 member of the group */
1855 DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
1856 (LPVOID)&cbContext, DPENUMGROUPS_ALL, bAnsi );
1858 /* Now delete player and player list from the sys group */
1859 DP_DeletePlayer( This, idPlayer );
1861 /* Let the SP know that we've destroyed this group */
1862 if( This->dp2->spData.lpCB->DeletePlayer )
1864 DPSP_DELETEPLAYERDATA data;
1866 FIXME( "data.dwFlags is incorrect\n" );
1868 data.idPlayer = idPlayer;
1869 data.dwFlags = 0;
1870 data.lpISP = This->dp2->spData.lpISP;
1872 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1875 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1877 return DP_OK;
1880 static BOOL CALLBACK
1881 cbDeletePlayerFromAllGroups(
1882 DPID dpId,
1883 DWORD dwPlayerType,
1884 LPCDPNAME lpName,
1885 DWORD dwFlags,
1886 LPVOID lpContext )
1888 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1890 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1892 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
1893 lpCtxt->bAnsi );
1895 /* Enumerate all groups in this group since this will normally only
1896 * be called for top level groups
1898 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
1899 dpId, NULL,
1900 cbDeletePlayerFromAllGroups,
1901 (LPVOID)lpContext, DPENUMGROUPS_ALL,
1902 lpCtxt->bAnsi );
1905 else
1907 ERR( "Group callback has dwPlayerType = 0x%08lx\n", dwPlayerType );
1910 return TRUE;
1913 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
1914 ( LPDIRECTPLAY2A iface, DPID idPlayer )
1916 ICOM_THIS(IDirectPlay2Impl,iface);
1917 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1920 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1921 ( LPDIRECTPLAY2 iface, DPID idPlayer )
1923 ICOM_THIS(IDirectPlay2Impl,iface);
1924 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1927 static HRESULT WINAPI DP_IF_EnumGroupPlayers
1928 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1929 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1930 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1932 lpGroupData lpGData;
1933 lpPlayerList lpPList;
1935 FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n",
1936 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1937 lpContext, dwFlags, bAnsi );
1939 /* Find the group */
1940 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1942 return DPERR_INVALIDGROUP;
1945 if( DPQ_IS_EMPTY( lpGData->players ) )
1947 return DP_OK;
1950 lpPList = DPQ_FIRST( lpGData->players );
1952 /* Walk the players in this group */
1953 for( ;; )
1955 /* We do not enum the name server or app server as they are of no
1956 * concequence to the end user.
1958 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
1959 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
1963 /* FIXME: Need to add stuff for dwFlags checking */
1965 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1966 &lpPList->lpPData->name,
1967 lpPList->lpPData->dwFlags,
1968 lpContext )
1971 /* User requested break */
1972 return DP_OK;
1976 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
1978 break;
1981 lpPList = DPQ_NEXT( lpPList->players );
1984 return DP_OK;
1987 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
1988 ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
1989 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1990 LPVOID lpContext, DWORD dwFlags )
1992 ICOM_THIS(IDirectPlay2Impl,iface);
1993 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
1994 lpEnumPlayersCallback2, lpContext,
1995 dwFlags, TRUE );
1998 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
1999 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
2000 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2001 LPVOID lpContext, DWORD dwFlags )
2003 ICOM_THIS(IDirectPlay2Impl,iface);
2004 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2005 lpEnumPlayersCallback2, lpContext,
2006 dwFlags, FALSE );
2009 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2010 static HRESULT WINAPI DP_IF_EnumGroups
2011 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2012 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2013 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2015 return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2016 DPID_SYSTEM_GROUP, lpguidInstance,
2017 lpEnumPlayersCallback2, lpContext,
2018 dwFlags, bAnsi );
2021 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2022 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2023 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2024 LPVOID lpContext, DWORD dwFlags )
2026 ICOM_THIS(IDirectPlay2Impl,iface);
2027 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2028 lpContext, dwFlags, TRUE );
2031 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2032 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2033 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2034 LPVOID lpContext, DWORD dwFlags )
2036 ICOM_THIS(IDirectPlay2Impl,iface);
2037 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2038 lpContext, dwFlags, FALSE );
2041 static HRESULT WINAPI DP_IF_EnumPlayers
2042 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2043 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2044 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2046 return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
2047 lpEnumPlayersCallback2, lpContext,
2048 dwFlags, bAnsi );
2051 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2052 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2053 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2054 LPVOID lpContext, DWORD dwFlags )
2056 ICOM_THIS(IDirectPlay2Impl,iface);
2057 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2058 lpContext, dwFlags, TRUE );
2061 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2062 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2063 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2064 LPVOID lpContext, DWORD dwFlags )
2066 ICOM_THIS(IDirectPlay2Impl,iface);
2067 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2068 lpContext, dwFlags, FALSE );
2071 /* This function should call the registered callback function that the user
2072 passed into EnumSessions for each entry available.
2074 static void DP_InvokeEnumSessionCallbacks
2075 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2076 LPVOID lpNSInfo,
2077 DWORD dwTimeout,
2078 LPVOID lpContext )
2080 LPDPSESSIONDESC2 lpSessionDesc;
2082 FIXME( ": not checking for conditions\n" );
2084 /* Not sure if this should be pruning but it's convenient */
2085 NS_PruneSessionCache( lpNSInfo );
2087 NS_ResetSessionEnumeration( lpNSInfo );
2089 /* Enumerate all sessions */
2090 /* FIXME: Need to indicate ANSI */
2091 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2093 TRACE( "EnumSessionsCallback2 invoked\n" );
2094 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2096 return;
2100 /* Invoke one last time to indicate that there is no more to come */
2101 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2104 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2106 EnumSessionAsyncCallbackData* data = (EnumSessionAsyncCallbackData*)lpContext;
2107 HANDLE hSuicideRequest = data->hSuicideRequest;
2108 DWORD dwTimeout = data->dwTimeout;
2110 TRACE( "Thread started with timeout = 0x%08lx\n", dwTimeout );
2112 for( ;; )
2114 HRESULT hr;
2116 /* Sleep up to dwTimeout waiting for request to terminate thread */
2117 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2119 TRACE( "Thread terminating on terminate request\n" );
2120 break;
2123 /* Now resend the enum request */
2124 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2125 data->dwEnumSessionFlags,
2126 data->lpSpData );
2128 if( FAILED(hr) )
2130 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2131 /* FIXME: Should we kill this thread? How to inform the main thread? */
2136 TRACE( "Thread terminating\n" );
2138 /* Clean up the thread data */
2139 CloseHandle( hSuicideRequest );
2140 HeapFree( GetProcessHeap(), 0, lpContext );
2142 /* FIXME: Need to have some notification to main app thread that this is
2143 * dead. It would serve two purposes. 1) allow sync on termination
2144 * so that we don't actually send something to ourselves when we
2145 * become name server (race condition) and 2) so that if we die
2146 * abnormally something else will be able to tell.
2149 return 1;
2152 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
2154 /* Does a thread exist? If so we were doing an async enum session */
2155 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2157 TRACE( "Killing EnumSession thread %u\n",
2158 This->dp2->hEnumSessionThread );
2160 /* Request that the thread kill itself nicely */
2161 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2162 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2164 /* We no longer need to know about the thread */
2165 CloseHandle( This->dp2->hEnumSessionThread );
2167 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2171 static HRESULT WINAPI DP_IF_EnumSessions
2172 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2173 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2174 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2176 HRESULT hr = DP_OK;
2178 TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx,%u)\n",
2179 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2180 bAnsi );
2182 /* Can't enumerate if the interface is already open */
2183 if( This->dp2->bConnectionOpen )
2185 return DPERR_GENERIC;
2188 #if 1
2189 /* The loading of a lobby provider _seems_ to require a backdoor loading
2190 * of the service provider to also associate with this DP object. This is
2191 * because the app doesn't seem to have to call EnumConnections and
2192 * InitializeConnection for the SP before calling this method. As such
2193 * we'll do their dirty work for them with a quick hack so as to always
2194 * load the TCP/IP service provider.
2196 * The correct solution would seem to involve creating a dialog box which
2197 * contains the possible SPs. These dialog boxes most likely follow SDK
2198 * examples.
2200 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2202 LPVOID lpConnection;
2203 DWORD dwSize;
2205 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2207 if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2209 ERR( "Can't build compound addr\n" );
2210 return DPERR_GENERIC;
2213 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2214 0, bAnsi );
2215 if( FAILED(hr) )
2217 return hr;
2220 /* Free up the address buffer */
2221 HeapFree( GetProcessHeap(), 0, lpConnection );
2223 /* The SP is now initialized */
2224 This->dp2->bSPInitialized = TRUE;
2226 #endif
2229 /* Use the service provider default? */
2230 if( dwTimeout == 0 )
2232 DPCAPS spCaps;
2233 spCaps.dwSize = sizeof( spCaps );
2235 DP_IF_GetCaps( This, &spCaps, 0 );
2236 dwTimeout = spCaps.dwTimeout;
2238 /* The service provider doesn't provide one either! */
2239 if( dwTimeout == 0 )
2241 /* Provide the TCP/IP default */
2242 dwTimeout = DPMSG_WAIT_5_SECS;
2246 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2248 DP_KillEnumSessionThread( This );
2249 return hr;
2252 /* FIXME: Interface locking sucks in this method */
2253 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2255 /* Enumerate everything presently in the local session cache */
2256 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2257 This->dp2->lpNameServerData, dwTimeout,
2258 lpContext );
2261 /* See if we've already created a thread to service this interface */
2262 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2264 DWORD dwThreadId;
2266 /* Send the first enum request inline since the user may cancel a dialog
2267 * if one is presented. Also, may also have a connecting return code.
2269 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2270 dwFlags, &This->dp2->spData );
2272 if( !FAILED(hr) )
2274 EnumSessionAsyncCallbackData* lpData
2275 = (EnumSessionAsyncCallbackData*)HeapAlloc( GetProcessHeap(),
2276 HEAP_ZERO_MEMORY,
2277 sizeof( *lpData ) );
2278 /* FIXME: need to kill the thread on object deletion */
2279 lpData->lpSpData = &This->dp2->spData;
2281 CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
2282 lpData->dwEnumSessionFlags = dwFlags;
2283 lpData->dwTimeout = dwTimeout;
2285 This->dp2->hKillEnumSessionThreadEvent =
2286 CreateEventA( NULL, TRUE, FALSE, NULL );
2288 if( !DuplicateHandle( GetCurrentProcess(),
2289 This->dp2->hKillEnumSessionThreadEvent,
2290 GetCurrentProcess(),
2291 &lpData->hSuicideRequest,
2292 0, FALSE, DUPLICATE_SAME_ACCESS )
2295 ERR( "Can't duplicate thread killing handle\n" );
2298 TRACE( ": creating EnumSessionsRequest thread\n" );
2300 This->dp2->hEnumSessionThread = CreateThread( NULL,
2302 DP_EnumSessionsSendAsyncRequestThread,
2303 lpData,
2305 &dwThreadId );
2309 else
2311 /* Invalidate the session cache for the interface */
2312 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2314 /* Send the broadcast for session enumeration */
2315 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2316 dwFlags,
2317 &This->dp2->spData );
2320 SleepEx( dwTimeout, FALSE );
2322 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2323 This->dp2->lpNameServerData, dwTimeout,
2324 lpContext );
2327 return hr;
2330 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2331 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2332 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2333 LPVOID lpContext, DWORD dwFlags )
2335 ICOM_THIS(IDirectPlay2Impl,iface);
2336 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2337 lpContext, dwFlags, TRUE );
2340 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2341 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2342 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2343 LPVOID lpContext, DWORD dwFlags )
2345 ICOM_THIS(IDirectPlay2Impl,iface);
2346 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2347 lpContext, dwFlags, FALSE );
2350 static HRESULT WINAPI DP_IF_GetPlayerCaps
2351 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2352 DWORD dwFlags )
2354 DPSP_GETCAPSDATA data;
2356 TRACE("(%p)->(0x%08lx,%p,0x%08lx)\n", This, idPlayer, lpDPCaps, dwFlags);
2358 /* Query the service provider */
2359 data.idPlayer = idPlayer;
2360 data.dwFlags = dwFlags;
2361 data.lpCaps = lpDPCaps;
2362 data.lpISP = This->dp2->spData.lpISP;
2364 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2367 static HRESULT WINAPI DP_IF_GetCaps
2368 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2370 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2373 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2374 ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2376 ICOM_THIS(IDirectPlay2Impl,iface);
2377 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2380 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2381 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2383 ICOM_THIS(IDirectPlay2Impl,iface);
2384 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2387 static HRESULT WINAPI DP_IF_GetGroupData
2388 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2389 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2391 lpGroupData lpGData;
2392 DWORD dwRequiredBufferSize;
2393 LPVOID lpCopyDataFrom;
2395 TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n",
2396 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2398 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2400 return DPERR_INVALIDGROUP;
2403 /* How much buffer is required? */
2404 if( dwFlags & DPSET_REMOTE )
2406 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2407 lpCopyDataFrom = lpGData->lpRemoteData;
2409 else if( dwFlags & DPSET_LOCAL )
2411 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2412 lpCopyDataFrom = lpGData->lpLocalData;
2414 else
2416 ERR( "Neither local or remote data requested!?!\n" );
2417 dwRequiredBufferSize = 0;
2418 lpCopyDataFrom = NULL;
2421 /* Is the user requesting to know how big a buffer is required? */
2422 if( ( lpData == NULL ) ||
2423 ( *lpdwDataSize < dwRequiredBufferSize )
2426 *lpdwDataSize = dwRequiredBufferSize;
2427 return DPERR_BUFFERTOOSMALL;
2430 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2432 return DP_OK;
2435 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2436 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2437 LPDWORD lpdwDataSize, DWORD dwFlags )
2439 ICOM_THIS(IDirectPlay2Impl,iface);
2440 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2441 dwFlags, TRUE );
2444 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2445 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2446 LPDWORD lpdwDataSize, DWORD dwFlags )
2448 ICOM_THIS(IDirectPlay2Impl,iface);
2449 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2450 dwFlags, FALSE );
2453 static HRESULT WINAPI DP_IF_GetGroupName
2454 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2455 LPDWORD lpdwDataSize, BOOL bAnsi )
2457 lpGroupData lpGData;
2458 LPDPNAME lpName = (LPDPNAME)lpData;
2459 DWORD dwRequiredDataSize;
2461 FIXME("(%p)->(0x%08lx,%p,%p,%u) ANSI ignored\n",
2462 This, idGroup, lpData, lpdwDataSize, bAnsi );
2464 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2466 return DPERR_INVALIDGROUP;
2469 dwRequiredDataSize = lpGData->name.dwSize;
2471 if( lpGData->name.u1.lpszShortNameA )
2473 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2476 if( lpGData->name.u2.lpszLongNameA )
2478 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2481 if( ( lpData == NULL ) ||
2482 ( *lpdwDataSize < dwRequiredDataSize )
2485 *lpdwDataSize = dwRequiredDataSize;
2486 return DPERR_BUFFERTOOSMALL;
2489 /* Copy the structure */
2490 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2492 if( lpGData->name.u1.lpszShortNameA )
2494 strcpy( ((BYTE*)lpName)+lpGData->name.dwSize,
2495 lpGData->name.u1.lpszShortNameA );
2497 else
2499 lpName->u1.lpszShortNameA = NULL;
2502 if( lpGData->name.u1.lpszShortNameA )
2504 strcpy( ((BYTE*)lpName)+lpGData->name.dwSize,
2505 lpGData->name.u2.lpszLongNameA );
2507 else
2509 lpName->u2.lpszLongNameA = NULL;
2512 return DP_OK;
2515 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2516 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2517 LPDWORD lpdwDataSize )
2519 ICOM_THIS(IDirectPlay2Impl,iface);
2520 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2523 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2524 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2525 LPDWORD lpdwDataSize )
2527 ICOM_THIS(IDirectPlay2Impl,iface);
2528 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2531 static HRESULT WINAPI DP_IF_GetMessageCount
2532 ( IDirectPlay2Impl* This, DPID idPlayer,
2533 LPDWORD lpdwCount, BOOL bAnsi )
2535 FIXME("(%p)->(0x%08lx,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2536 return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2537 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2538 bAnsi );
2541 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2542 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2544 ICOM_THIS(IDirectPlay2Impl,iface);
2545 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2548 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2549 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2551 ICOM_THIS(IDirectPlay2Impl,iface);
2552 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2555 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2556 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2558 ICOM_THIS(IDirectPlay2Impl,iface);
2559 FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2560 return DP_OK;
2563 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2564 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2566 ICOM_THIS(IDirectPlay2Impl,iface);
2567 FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2568 return DP_OK;
2571 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2572 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2573 DWORD dwFlags )
2575 ICOM_THIS(IDirectPlay2Impl,iface);
2576 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2579 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2580 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2581 DWORD dwFlags )
2583 ICOM_THIS(IDirectPlay2Impl,iface);
2584 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2587 static HRESULT WINAPI DP_IF_GetPlayerData
2588 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2589 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2591 lpPlayerList lpPList;
2592 DWORD dwRequiredBufferSize;
2593 LPVOID lpCopyDataFrom;
2595 TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n",
2596 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2598 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2600 return DPERR_INVALIDPLAYER;
2603 /* How much buffer is required? */
2604 if( dwFlags & DPSET_REMOTE )
2606 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2607 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2609 else if( dwFlags & DPSET_LOCAL )
2611 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2612 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2614 else
2616 ERR( "Neither local or remote data requested!?!\n" );
2617 dwRequiredBufferSize = 0;
2618 lpCopyDataFrom = NULL;
2621 /* Is the user requesting to know how big a buffer is required? */
2622 if( ( lpData == NULL ) ||
2623 ( *lpdwDataSize < dwRequiredBufferSize )
2626 *lpdwDataSize = dwRequiredBufferSize;
2627 return DPERR_BUFFERTOOSMALL;
2630 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2632 return DP_OK;
2635 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2636 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2637 LPDWORD lpdwDataSize, DWORD dwFlags )
2639 ICOM_THIS(IDirectPlay2Impl,iface);
2640 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2641 dwFlags, TRUE );
2644 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2645 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2646 LPDWORD lpdwDataSize, DWORD dwFlags )
2648 ICOM_THIS(IDirectPlay2Impl,iface);
2649 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2650 dwFlags, FALSE );
2653 static HRESULT WINAPI DP_IF_GetPlayerName
2654 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2655 LPDWORD lpdwDataSize, BOOL bAnsi )
2657 lpPlayerList lpPList;
2658 LPDPNAME lpName = (LPDPNAME)lpData;
2659 DWORD dwRequiredDataSize;
2661 FIXME( "(%p)->(0x%08lx,%p,%p,%u): ANSI \n",
2662 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2664 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2666 return DPERR_INVALIDPLAYER;
2669 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2671 if( lpPList->lpPData->name.u1.lpszShortNameA )
2673 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2676 if( lpPList->lpPData->name.u2.lpszLongNameA )
2678 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2681 if( ( lpData == NULL ) ||
2682 ( *lpdwDataSize < dwRequiredDataSize )
2685 *lpdwDataSize = dwRequiredDataSize;
2686 return DPERR_BUFFERTOOSMALL;
2689 /* Copy the structure */
2690 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2692 if( lpPList->lpPData->name.u1.lpszShortNameA )
2694 strcpy( ((BYTE*)lpName)+lpPList->lpPData->name.dwSize,
2695 lpPList->lpPData->name.u1.lpszShortNameA );
2697 else
2699 lpName->u1.lpszShortNameA = NULL;
2702 if( lpPList->lpPData->name.u1.lpszShortNameA )
2704 strcpy( ((BYTE*)lpName)+lpPList->lpPData->name.dwSize,
2705 lpPList->lpPData->name.u2.lpszLongNameA );
2707 else
2709 lpName->u2.lpszLongNameA = NULL;
2712 return DP_OK;
2715 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2716 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2717 LPDWORD lpdwDataSize )
2719 ICOM_THIS(IDirectPlay2Impl,iface);
2720 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2723 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2724 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2725 LPDWORD lpdwDataSize )
2727 ICOM_THIS(IDirectPlay2Impl,iface);
2728 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2731 static HRESULT WINAPI DP_GetSessionDesc
2732 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2733 BOOL bAnsi )
2735 DWORD dwRequiredSize;
2737 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2739 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2741 return DPERR_INVALIDPARAMS;
2744 /* FIXME: Get from This->dp2->lpSessionDesc */
2745 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2747 if ( ( lpData == NULL ) ||
2748 ( *lpdwDataSize < dwRequiredSize )
2751 *lpdwDataSize = dwRequiredSize;
2752 return DPERR_BUFFERTOOSMALL;
2755 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2757 return DP_OK;
2760 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2761 ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2763 ICOM_THIS(IDirectPlay2Impl,iface);
2764 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2767 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2768 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2770 ICOM_THIS(IDirectPlay2Impl,iface);
2771 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2774 /* Intended only for COM compatibility. Always returns an error. */
2775 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2776 ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2778 ICOM_THIS(IDirectPlay2Impl,iface);
2779 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2780 return DPERR_ALREADYINITIALIZED;
2783 /* Intended only for COM compatibility. Always returns an error. */
2784 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2785 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2787 ICOM_THIS(IDirectPlay2Impl,iface);
2788 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2789 return DPERR_ALREADYINITIALIZED;
2793 static HRESULT WINAPI DP_SecureOpen
2794 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2795 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2796 BOOL bAnsi )
2798 HRESULT hr = DP_OK;
2800 FIXME( "(%p)->(%p,0x%08lx,%p,%p): partial stub\n",
2801 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2803 if( This->dp2->bConnectionOpen )
2805 TRACE( ": rejecting already open connection.\n" );
2806 return DPERR_ALREADYINITIALIZED;
2809 /* If we're enumerating, kill the thread */
2810 DP_KillEnumSessionThread( This );
2812 if( dwFlags & DPOPEN_CREATE )
2814 /* Rightoo - this computer is the host and the local computer needs to be
2815 the name server so that others can join this session */
2816 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2818 This->dp2->bHostInterface = TRUE;
2820 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2821 if( FAILED( hr ) )
2823 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2824 return hr;
2828 /* Invoke the conditional callback for the service provider */
2829 if( This->dp2->spData.lpCB->Open )
2831 DPSP_OPENDATA data;
2833 FIXME( "Not all data fields are correct. Need new parameter\n" );
2835 data.bCreate = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
2836 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2837 : NS_GetNSAddr( This->dp2->lpNameServerData );
2838 data.lpISP = This->dp2->spData.lpISP;
2839 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
2840 data.dwOpenFlags = dwFlags;
2841 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2843 hr = (*This->dp2->spData.lpCB->Open)(&data);
2844 if( FAILED( hr ) )
2846 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2847 return hr;
2852 /* Create the system group of which everything is a part of */
2853 DPID systemGroup = DPID_SYSTEM_GROUP;
2855 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2856 NULL, 0, 0, TRUE );
2860 if( dwFlags & DPOPEN_JOIN )
2862 DPID dpidServerId = DPID_UNKNOWN;
2864 /* Create the server player for this interface. This way we can receive
2865 * messages for this session.
2867 /* FIXME: I suppose that we should be setting an event for a receive
2868 * type of thing. That way the messaging thread could know to wake
2869 * up. DPlay would then trigger the hEvent for the player the
2870 * message is directed to.
2872 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2874 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2877 else if( dwFlags & DPOPEN_CREATE )
2879 DPID dpidNameServerId = DPID_NAME_SERVER;
2881 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2882 0, DPPLAYER_SERVERPLAYER, bAnsi );
2885 if( FAILED(hr) )
2887 ERR( "Couldn't create name server/system player: %s\n",
2888 DPLAYX_HresultToString(hr) );
2891 return hr;
2894 static HRESULT WINAPI DirectPlay2AImpl_Open
2895 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2897 ICOM_THIS(IDirectPlay2Impl,iface);
2898 TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
2899 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
2902 static HRESULT WINAPI DirectPlay2WImpl_Open
2903 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2905 ICOM_THIS(IDirectPlay2Impl,iface);
2906 TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
2907 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
2910 static HRESULT WINAPI DP_IF_Receive
2911 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2912 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2914 LPDPMSG lpMsg = NULL;
2916 FIXME( "(%p)->(%p,%p,0x%08lx,%p,%p,%u): stub\n",
2917 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2919 if( dwFlags == 0 )
2921 dwFlags = DPRECEIVE_ALL;
2924 /* If the lpData is NULL, we must be peeking the message */
2925 if( ( lpData == NULL ) &&
2926 !( dwFlags & DPRECEIVE_PEEK )
2929 return DPERR_INVALIDPARAMS;
2932 if( dwFlags & DPRECEIVE_ALL )
2934 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2936 if( !( dwFlags & DPRECEIVE_PEEK ) )
2938 FIXME( "Remove from queue\n" );
2941 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2942 ( dwFlags & DPRECEIVE_FROMPLAYER )
2945 FIXME( "Find matching message 0x%08lx\n", dwFlags );
2947 else
2949 ERR( "Hmmm..dwFlags 0x%08lx\n", dwFlags );
2952 if( lpMsg == NULL )
2954 return DPERR_NOMESSAGES;
2957 /* Copy into the provided buffer */
2958 CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
2960 return DP_OK;
2963 static HRESULT WINAPI DirectPlay2AImpl_Receive
2964 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
2965 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2967 ICOM_THIS(IDirectPlay2Impl,iface);
2968 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2969 lpData, lpdwDataSize, TRUE );
2972 static HRESULT WINAPI DirectPlay2WImpl_Receive
2973 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
2974 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2976 ICOM_THIS(IDirectPlay2Impl,iface);
2977 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2978 lpData, lpdwDataSize, FALSE );
2981 static HRESULT WINAPI DirectPlay2AImpl_Send
2982 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
2984 ICOM_THIS(IDirectPlay2Impl,iface);
2985 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
2986 0, 0, NULL, NULL, TRUE );
2989 static HRESULT WINAPI DirectPlay2WImpl_Send
2990 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
2992 ICOM_THIS(IDirectPlay2Impl,iface);
2993 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
2994 0, 0, NULL, NULL, FALSE );
2997 static HRESULT WINAPI DP_IF_SetGroupData
2998 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2999 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3001 lpGroupData lpGData;
3003 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n",
3004 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3006 /* Parameter check */
3007 if( ( lpData == NULL ) &&
3008 ( dwDataSize != 0 )
3011 return DPERR_INVALIDPARAMS;
3014 /* Find the pointer to the data for this player */
3015 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3017 return DPERR_INVALIDOBJECT;
3020 if( dwFlags & DPSET_REMOTE )
3022 FIXME( "Was this group created by this interface?\n" );
3023 /* FIXME: If this is a remote update need to allow it but not
3024 * send a message.
3028 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3030 /* FIXME: Only send a message if this group is local to the session otherwise
3031 * it will have been rejected above
3033 if( dwFlags & DPSET_REMOTE )
3035 FIXME( "Send msg?\n" );
3038 return DP_OK;
3041 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3042 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3043 DWORD dwDataSize, DWORD dwFlags )
3045 ICOM_THIS(IDirectPlay2Impl,iface);
3046 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3049 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3050 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3051 DWORD dwDataSize, DWORD dwFlags )
3053 ICOM_THIS(IDirectPlay2Impl,iface);
3054 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3057 static HRESULT WINAPI DP_IF_SetGroupName
3058 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3059 DWORD dwFlags, BOOL bAnsi )
3061 lpGroupData lpGData;
3063 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", This, idGroup,
3064 lpGroupName, dwFlags, bAnsi );
3066 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3068 return DPERR_INVALIDGROUP;
3071 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3073 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3074 FIXME( "Message not sent and dwFlags ignored\n" );
3076 return DP_OK;
3079 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3080 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3081 DWORD dwFlags )
3083 ICOM_THIS(IDirectPlay2Impl,iface);
3084 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3087 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3088 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3089 DWORD dwFlags )
3091 ICOM_THIS(IDirectPlay2Impl,iface);
3092 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3095 static HRESULT WINAPI DP_IF_SetPlayerData
3096 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3097 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3099 lpPlayerList lpPList;
3101 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n",
3102 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3104 /* Parameter check */
3105 if( ( lpData == NULL ) &&
3106 ( dwDataSize != 0 )
3109 return DPERR_INVALIDPARAMS;
3112 /* Find the pointer to the data for this player */
3113 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3115 return DPERR_INVALIDPLAYER;
3118 if( dwFlags & DPSET_REMOTE )
3120 FIXME( "Was this group created by this interface?\n" );
3121 /* FIXME: If this is a remote update need to allow it but not
3122 * send a message.
3126 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3128 if( dwFlags & DPSET_REMOTE )
3130 FIXME( "Send msg?\n" );
3133 return DP_OK;
3136 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3137 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3138 DWORD dwDataSize, DWORD dwFlags )
3140 ICOM_THIS(IDirectPlay2Impl,iface);
3141 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3142 dwFlags, TRUE );
3145 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3146 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3147 DWORD dwDataSize, DWORD dwFlags )
3149 ICOM_THIS(IDirectPlay2Impl,iface);
3150 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3151 dwFlags, FALSE );
3154 static HRESULT WINAPI DP_IF_SetPlayerName
3155 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3156 DWORD dwFlags, BOOL bAnsi )
3158 lpPlayerList lpPList;
3160 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n",
3161 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3163 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3165 return DPERR_INVALIDGROUP;
3168 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3170 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3171 FIXME( "Message not sent and dwFlags ignored\n" );
3173 return DP_OK;
3176 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3177 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3178 DWORD dwFlags )
3180 ICOM_THIS(IDirectPlay2Impl,iface);
3181 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3184 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3185 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3186 DWORD dwFlags )
3188 ICOM_THIS(IDirectPlay2Impl,iface);
3189 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3192 static HRESULT WINAPI DP_SetSessionDesc
3193 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3194 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3196 DWORD dwRequiredSize;
3197 LPDPSESSIONDESC2 lpTempSessDesc;
3199 TRACE( "(%p)->(%p,0x%08lx,%u,%u)\n",
3200 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3202 if( dwFlags )
3204 return DPERR_INVALIDPARAMS;
3207 /* Only the host is allowed to update the session desc */
3208 if( !This->dp2->bHostInterface )
3210 return DPERR_ACCESSDENIED;
3213 /* FIXME: Copy into This->dp2->lpSessionDesc */
3214 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3215 lpTempSessDesc = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(),
3216 HEAP_ZERO_MEMORY,
3217 dwRequiredSize );
3219 if( lpTempSessDesc == NULL )
3221 return DPERR_OUTOFMEMORY;
3224 /* Free the old */
3225 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3227 This->dp2->lpSessionDesc = lpTempSessDesc;
3229 /* Set the new */
3230 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3232 /* If this is an external invocation of the interface, we should be
3233 * letting everyone know that things have changed. Otherwise this is
3234 * just an initialization and it doesn't need to be propagated.
3236 if( !bInitial )
3238 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3241 return DP_OK;
3244 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3245 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3247 ICOM_THIS(IDirectPlay2Impl,iface);
3248 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3251 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3252 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3254 ICOM_THIS(IDirectPlay2Impl,iface);
3255 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3258 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3259 DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3261 DWORD dwSize = 0;
3263 if( lpSessDesc == NULL )
3265 /* Hmmm..don't need any size? */
3266 ERR( "NULL lpSessDesc\n" );
3267 return dwSize;
3270 dwSize += sizeof( *lpSessDesc );
3272 if( bAnsi )
3274 if( lpSessDesc->u1.lpszSessionNameA )
3276 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3279 if( lpSessDesc->u2.lpszPasswordA )
3281 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3284 else /* UNICODE */
3286 if( lpSessDesc->u1.lpszSessionName )
3288 dwSize += sizeof( WCHAR ) *
3289 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3292 if( lpSessDesc->u2.lpszPassword )
3294 dwSize += sizeof( WCHAR ) *
3295 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3299 return dwSize;
3302 /* Assumes that contugous buffers are already allocated. */
3303 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3304 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3306 BYTE* lpStartOfFreeSpace;
3308 if( lpSessionDest == NULL )
3310 ERR( "NULL lpSessionDest\n" );
3311 return;
3314 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3316 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3318 if( bAnsi )
3320 if( lpSessionSrc->u1.lpszSessionNameA )
3322 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3323 lpSessionDest->u1.lpszSessionNameA );
3324 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3325 lpStartOfFreeSpace +=
3326 lstrlenA( (LPSTR)lpSessionDest->u1.lpszSessionNameA ) + 1;
3329 if( lpSessionSrc->u2.lpszPasswordA )
3331 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3332 lpSessionDest->u2.lpszPasswordA );
3333 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3334 lpStartOfFreeSpace +=
3335 lstrlenA( (LPSTR)lpSessionDest->u2.lpszPasswordA ) + 1;
3338 else /* UNICODE */
3340 if( lpSessionSrc->u1.lpszSessionName )
3342 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3343 lpSessionDest->u1.lpszSessionName );
3344 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3345 lpStartOfFreeSpace += sizeof(WCHAR) *
3346 ( lstrlenW( (LPWSTR)lpSessionDest->u1.lpszSessionName ) + 1 );
3349 if( lpSessionSrc->u2.lpszPassword )
3351 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3352 lpSessionDest->u2.lpszPassword );
3353 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3354 lpStartOfFreeSpace += sizeof(WCHAR) *
3355 ( lstrlenW( (LPWSTR)lpSessionDest->u2.lpszPassword ) + 1 );
3361 static HRESULT WINAPI DP_IF_AddGroupToGroup
3362 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3364 lpGroupData lpGParentData;
3365 lpGroupData lpGData;
3366 lpGroupList lpNewGList;
3368 TRACE( "(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
3370 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3372 return DPERR_INVALIDGROUP;
3375 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3377 return DPERR_INVALIDGROUP;
3380 /* Create a player list (ie "shortcut" ) */
3381 lpNewGList = (lpGroupList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3382 sizeof( *lpNewGList ) );
3383 if( lpNewGList == NULL )
3385 return DPERR_CANTADDPLAYER;
3388 /* Add the shortcut */
3389 lpGData->uRef++;
3390 lpNewGList->lpGData = lpGData;
3392 /* Add the player to the list of players for this group */
3393 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3395 /* Send a ADDGROUPTOGROUP message */
3396 FIXME( "Not sending message\n" );
3398 return DP_OK;
3401 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3402 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3404 ICOM_THIS(IDirectPlay3Impl,iface);
3405 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3408 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3409 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3411 ICOM_THIS(IDirectPlay3Impl,iface);
3412 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3415 static HRESULT WINAPI DP_IF_CreateGroupInGroup
3416 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3417 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3418 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3420 lpGroupData lpGParentData;
3421 lpGroupList lpGList;
3422 lpGroupData lpGData;
3424 TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
3425 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3426 dwDataSize, dwFlags, bAnsi );
3428 /* Verify that the specified parent is valid */
3429 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3430 idParentGroup ) ) == NULL
3433 return DPERR_INVALIDGROUP;
3436 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3437 dwFlags, idParentGroup, bAnsi );
3439 if( lpGData == NULL )
3441 return DPERR_CANTADDPLAYER; /* yes player not group */
3444 /* Something else is referencing this data */
3445 lpGData->uRef++;
3447 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3449 /* The list has now been inserted into the interface group list. We now
3450 need to put a "shortcut" to this group in the parent group */
3451 lpGList = (lpGroupList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3452 sizeof( *lpGList ) );
3453 if( lpGList == NULL )
3455 FIXME( "Memory leak\n" );
3456 return DPERR_CANTADDPLAYER; /* yes player not group */
3459 lpGList->lpGData = lpGData;
3461 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3463 /* Let the SP know that we've created this group */
3464 if( This->dp2->spData.lpCB->CreateGroup )
3466 DPSP_CREATEGROUPDATA data;
3468 TRACE( "Calling SP CreateGroup\n" );
3470 data.idGroup = *lpidGroup;
3471 data.dwFlags = dwFlags;
3472 data.lpSPMessageHeader = lpMsgHdr;
3473 data.lpISP = This->dp2->spData.lpISP;
3475 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3478 /* Inform all other peers of the creation of a new group. If there are
3479 * no peers keep this quiet.
3481 if( This->dp2->lpSessionDesc &&
3482 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3484 DPMSG_CREATEPLAYERORGROUP msg;
3486 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3487 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3488 msg.dpId = *lpidGroup;
3489 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3490 msg.lpData = lpData;
3491 msg.dwDataSize = dwDataSize;
3492 msg.dpnName = *lpGroupName;
3494 /* FIXME: Correct to just use send effectively? */
3495 /* FIXME: Should size include data w/ message or just message "header" */
3496 /* FIXME: Check return code */
3497 DP_SendEx( (IDirectPlay2Impl*)This,
3498 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3499 0, 0, NULL, NULL, bAnsi );
3502 return DP_OK;
3505 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3506 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3507 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3508 DWORD dwFlags )
3510 ICOM_THIS(IDirectPlay3Impl,iface);
3512 *lpidGroup = DPID_UNKNOWN;
3514 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3515 lpGroupName, lpData, dwDataSize, dwFlags,
3516 TRUE );
3519 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3520 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3521 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3522 DWORD dwFlags )
3524 ICOM_THIS(IDirectPlay3Impl,iface);
3526 *lpidGroup = DPID_UNKNOWN;
3528 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3529 lpGroupName, lpData, dwDataSize,
3530 dwFlags, FALSE );
3533 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
3534 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3536 lpGroupList lpGList;
3537 lpGroupData lpGParentData;
3539 TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
3541 /* Is the parent group valid? */
3542 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3544 return DPERR_INVALIDGROUP;
3547 /* Remove the group from the parent group queue */
3548 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3550 if( lpGList == NULL )
3552 return DPERR_INVALIDGROUP;
3555 /* Decrement the ref count */
3556 lpGList->lpGData->uRef--;
3558 /* Free up the list item */
3559 HeapFree( GetProcessHeap(), 0, lpGList );
3561 /* Should send a DELETEGROUPFROMGROUP message */
3562 FIXME( "message not sent\n" );
3564 return DP_OK;
3567 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3568 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3570 ICOM_THIS(IDirectPlay3Impl,iface);
3571 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3574 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3575 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3577 ICOM_THIS(IDirectPlay3Impl,iface);
3578 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3581 static
3582 BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3583 LPDWORD lpdwBufSize )
3585 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3586 HRESULT hr;
3588 dpCompoundAddress.dwDataSize = sizeof( GUID );
3589 memcpy( &dpCompoundAddress.guidDataType, &DPAID_ServiceProvider,
3590 sizeof( GUID ) ) ;
3591 dpCompoundAddress.lpData = lpcSpGuid;
3593 *lplpAddrBuf = NULL;
3594 *lpdwBufSize = 0;
3596 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3597 lpdwBufSize, TRUE );
3599 if( hr != DPERR_BUFFERTOOSMALL )
3601 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3602 return FALSE;
3605 /* Now allocate the buffer */
3606 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3607 *lpdwBufSize );
3609 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3610 lpdwBufSize, TRUE );
3611 if( FAILED(hr) )
3613 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3614 return FALSE;
3617 return TRUE;
3620 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
3621 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3623 ICOM_THIS(IDirectPlay3Impl,iface);
3624 TRACE("(%p)->(%p,%p,%p,0x%08lx)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3626 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3627 if( dwFlags == 0 )
3629 dwFlags = DPCONNECTION_DIRECTPLAY;
3632 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3633 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3636 return DPERR_INVALIDFLAGS;
3639 if( !lpEnumCallback || !*lpEnumCallback )
3641 return DPERR_INVALIDPARAMS;
3644 /* Enumerate DirectPlay service providers */
3645 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3647 HKEY hkResult;
3648 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3649 LPSTR guidDataSubKey = "Guid";
3650 char subKeyName[51];
3651 DWORD dwIndex, sizeOfSubKeyName=50;
3652 FILETIME filetime;
3654 /* Need to loop over the service providers in the registry */
3655 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3656 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3658 /* Hmmm. Does this mean that there are no service providers? */
3659 ERR(": no service providers?\n");
3660 return DP_OK;
3664 /* Traverse all the service providers we have available */
3665 for( dwIndex=0;
3666 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3667 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3668 ++dwIndex, sizeOfSubKeyName=51 )
3671 HKEY hkServiceProvider;
3672 GUID serviceProviderGUID;
3673 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3674 char returnBuffer[51];
3675 WCHAR buff[51];
3676 DPNAME dpName;
3677 BOOL bBuildPass;
3679 LPVOID lpAddressBuffer = NULL;
3680 DWORD dwAddressBufferSize = 0;
3682 TRACE(" this time through: %s\n", subKeyName );
3684 /* Get a handle for this particular service provider */
3685 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3686 &hkServiceProvider ) != ERROR_SUCCESS )
3688 ERR(": what the heck is going on?\n" );
3689 continue;
3692 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3693 NULL, &returnTypeGUID, returnBuffer,
3694 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3696 ERR(": missing GUID registry data members\n" );
3697 continue;
3700 /* FIXME: Check return types to ensure we're interpreting data right */
3701 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3702 CLSIDFromString( (LPCOLESTR)buff, &serviceProviderGUID );
3703 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3705 /* Fill in the DPNAME struct for the service provider */
3706 dpName.dwSize = sizeof( dpName );
3707 dpName.dwFlags = 0;
3708 dpName.u1.lpszShortNameA = subKeyName;
3709 dpName.u2.lpszLongNameA = NULL;
3711 /* Create the compound address for the service provider.
3712 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3713 nast stuff. This may be why the native dll just gets around this little bit by
3714 allocating an 80 byte buffer which isn't even a filled with a valid compound
3715 address. Oh well. Creating a proper compound address is the way to go anyways
3716 despite this method taking slightly more heap space and realtime :) */
3718 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3719 &lpAddressBuffer,
3720 &dwAddressBufferSize );
3721 if( !bBuildPass )
3723 ERR( "Can't build compound addr\n" );
3724 return DPERR_GENERIC;
3727 /* The enumeration will return FALSE if we are not to continue */
3728 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3729 &dpName, DPCONNECTION_DIRECTPLAY, lpContext ) )
3731 return DP_OK;
3736 /* Enumerate DirectPlayLobby service providers */
3737 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3739 HKEY hkResult;
3740 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3741 LPSTR guidDataSubKey = "Guid";
3742 char subKeyName[51];
3743 DWORD dwIndex, sizeOfSubKeyName=50;
3744 FILETIME filetime;
3746 /* Need to loop over the service providers in the registry */
3747 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3748 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3750 /* Hmmm. Does this mean that there are no service providers? */
3751 ERR(": no service providers?\n");
3752 return DP_OK;
3756 /* Traverse all the lobby providers we have available */
3757 for( dwIndex=0;
3758 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3759 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3760 ++dwIndex, sizeOfSubKeyName=51 )
3763 HKEY hkServiceProvider;
3764 GUID serviceProviderGUID;
3765 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3766 char returnBuffer[51];
3767 WCHAR buff[51];
3768 DPNAME dpName;
3769 HRESULT hr;
3771 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3772 LPVOID lpAddressBuffer = NULL;
3773 DWORD dwAddressBufferSize = 0;
3775 TRACE(" this time through: %s\n", subKeyName );
3777 /* Get a handle for this particular service provider */
3778 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3779 &hkServiceProvider ) != ERROR_SUCCESS )
3781 ERR(": what the heck is going on?\n" );
3782 continue;
3785 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3786 NULL, &returnTypeGUID, returnBuffer,
3787 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3789 ERR(": missing GUID registry data members\n" );
3790 continue;
3793 /* FIXME: Check return types to ensure we're interpreting data right */
3794 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3795 CLSIDFromString( (LPCOLESTR)buff, &serviceProviderGUID );
3796 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3798 /* Fill in the DPNAME struct for the service provider */
3799 dpName.dwSize = sizeof( dpName );
3800 dpName.dwFlags = 0;
3801 dpName.u1.lpszShortNameA = subKeyName;
3802 dpName.u2.lpszLongNameA = NULL;
3804 /* Create the compound address for the service provider.
3805 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3806 nast stuff. This may be why the native dll just gets around this little bit by
3807 allocating an 80 byte buffer which isn't even a filled with a valid compound
3808 address. Oh well. Creating a proper compound address is the way to go anyways
3809 despite this method taking slightly more heap space and realtime :) */
3811 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3812 dpCompoundAddress.dwDataSize = sizeof( GUID );
3813 dpCompoundAddress.lpData = &serviceProviderGUID;
3815 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3816 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3818 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3819 return hr;
3822 /* Now allocate the buffer */
3823 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3825 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3826 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3828 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3829 return hr;
3832 /* The enumeration will return FALSE if we are not to continue */
3833 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3834 &dpName, DPCONNECTION_DIRECTPLAYLOBBY, lpContext ) )
3836 return DP_OK;
3841 return DP_OK;
3844 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3845 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3847 ICOM_THIS(IDirectPlay3Impl,iface);
3848 FIXME("(%p)->(%p,%p,%p,0x%08lx): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3849 return DP_OK;
3852 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
3853 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3854 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3855 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3857 lpGroupList lpGList;
3858 lpGroupData lpGData;
3860 FIXME( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n",
3861 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3862 lpContext, dwFlags, bAnsi );
3864 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3866 return DPERR_INVALIDGROUP;
3869 if( DPQ_IS_EMPTY( lpGData->groups ) )
3871 return DP_OK;
3874 lpGList = DPQ_FIRST( lpGData->groups );
3876 for( ;; )
3878 /* FIXME: Should check dwFlags for match here */
3880 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3881 &lpGList->lpGData->name, dwFlags,
3882 lpContext ) )
3884 return DP_OK; /* User requested break */
3887 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3889 break;
3892 lpGList = DPQ_NEXT( lpGList->groups );
3896 return DP_OK;
3899 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
3900 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3901 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3902 DWORD dwFlags )
3904 ICOM_THIS(IDirectPlay3Impl,iface);
3905 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3906 lpEnumPlayersCallback2, lpContext, dwFlags,
3907 TRUE );
3910 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3911 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3912 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3913 DWORD dwFlags )
3915 ICOM_THIS(IDirectPlay3Impl,iface);
3916 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3917 lpEnumPlayersCallback2, lpContext, dwFlags,
3918 FALSE );
3921 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
3922 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3924 ICOM_THIS(IDirectPlay3Impl,iface);
3925 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3926 return DP_OK;
3929 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
3930 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3932 ICOM_THIS(IDirectPlay3Impl,iface);
3933 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3934 return DP_OK;
3937 BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
3938 REFGUID guidDataType,
3939 DWORD dwDataSize,
3940 LPCVOID lpData,
3941 LPVOID lpContext )
3943 /* Looking for the GUID of the provider to load */
3944 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
3945 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
3948 TRACE( "Found SP/LP (%s) %s (data size = 0x%08lx)\n",
3949 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
3951 if( dwDataSize != sizeof( GUID ) )
3953 ERR( "Invalid sp/lp guid size 0x%08lx\n", dwDataSize );
3956 memcpy( lpContext, lpData, dwDataSize );
3958 /* There shouldn't be more than 1 GUID/compound address */
3959 return FALSE;
3962 /* Still waiting for what we want */
3963 return TRUE;
3967 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
3968 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
3970 UINT i;
3971 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3972 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3973 LPCSTR guidDataSubKey = "Guid";
3974 LPCSTR majVerDataSubKey = "dwReserved1";
3975 LPCSTR minVerDataSubKey = "dwReserved2";
3976 LPCSTR pathSubKey = "Path";
3978 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
3980 /* FIXME: Cloned code with a quick hack. */
3981 for( i=0; i<2; i++ )
3983 HKEY hkResult;
3984 LPCSTR searchSubKey;
3985 char subKeyName[51];
3986 DWORD dwIndex, sizeOfSubKeyName=50;
3987 FILETIME filetime;
3989 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
3990 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
3993 /* Need to loop over the service providers in the registry */
3994 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3995 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3997 /* Hmmm. Does this mean that there are no service providers? */
3998 ERR(": no service providers?\n");
3999 return 0;
4002 /* Traverse all the service providers we have available */
4003 for( dwIndex=0;
4004 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4005 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4006 ++dwIndex, sizeOfSubKeyName=51 )
4009 HKEY hkServiceProvider;
4010 GUID serviceProviderGUID;
4011 DWORD returnType, sizeOfReturnBuffer = 255;
4012 char returnBuffer[256];
4013 WCHAR buff[51];
4014 DWORD dwTemp, len;
4016 TRACE(" this time through: %s\n", subKeyName );
4018 /* Get a handle for this particular service provider */
4019 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4020 &hkServiceProvider ) != ERROR_SUCCESS )
4022 ERR(": what the heck is going on?\n" );
4023 continue;
4026 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4027 NULL, &returnType, returnBuffer,
4028 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4030 ERR(": missing GUID registry data members\n" );
4031 continue;
4034 /* FIXME: Check return types to ensure we're interpreting data right */
4035 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4036 CLSIDFromString( (LPCOLESTR)buff, &serviceProviderGUID );
4037 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4039 /* Determine if this is the Service Provider that the user asked for */
4040 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4042 continue;
4045 if( i == 0 ) /* DP SP */
4047 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4048 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4049 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4052 sizeOfReturnBuffer = 255;
4054 /* Get dwReserved1 */
4055 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4056 NULL, &returnType, returnBuffer,
4057 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4059 ERR(": missing dwReserved1 registry data members\n") ;
4060 continue;
4063 if( i == 0 )
4065 lpSpData->dwReserved1 = GET_DWORD( returnBuffer );
4068 sizeOfReturnBuffer = 255;
4070 /* Get dwReserved2 */
4071 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4072 NULL, &returnType, returnBuffer,
4073 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4075 ERR(": missing dwReserved1 registry data members\n") ;
4076 continue;
4079 if( i == 0 )
4081 lpSpData->dwReserved2 = GET_DWORD( returnBuffer );
4084 sizeOfReturnBuffer = 255;
4086 /* Get the path for this service provider */
4087 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4088 NULL, NULL, returnBuffer,
4089 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4091 ERR(": missing PATH registry data members: 0x%08lx\n", dwTemp );
4092 continue;
4095 TRACE( "Loading %s\n", returnBuffer );
4096 return LoadLibraryA( returnBuffer );
4100 return 0;
4103 static
4104 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4106 HRESULT hr;
4107 LPDPSP_SPINIT SPInit;
4109 /* Initialize the service provider by calling SPInit */
4110 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4112 if( SPInit == NULL )
4114 ERR( "Service provider doesn't provide SPInit interface?\n" );
4115 FreeLibrary( hServiceProvider );
4116 return DPERR_UNAVAILABLE;
4119 TRACE( "Calling SPInit (DP SP entry point)\n" );
4121 hr = (*SPInit)( &This->dp2->spData );
4123 if( FAILED(hr) )
4125 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4126 FreeLibrary( hServiceProvider );
4127 return hr;
4130 /* FIXME: Need to verify the sanity of the returned callback table
4131 * using IsBadCodePtr */
4132 This->dp2->bSPInitialized = TRUE;
4134 /* This interface is now initialized as a DP object */
4135 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4137 /* Store the handle of the module so that we can unload it later */
4138 This->dp2->hServiceProvider = hServiceProvider;
4140 return hr;
4143 static
4144 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4146 HRESULT hr;
4147 LPSP_INIT DPLSPInit;
4149 /* Initialize the service provider by calling SPInit */
4150 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4152 if( DPLSPInit == NULL )
4154 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4155 FreeLibrary( hLobbyProvider );
4156 return DPERR_UNAVAILABLE;
4159 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4161 hr = (*DPLSPInit)( &This->dp2->dplspData );
4163 if( FAILED(hr) )
4165 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4166 FreeLibrary( hLobbyProvider );
4167 return hr;
4170 /* FIXME: Need to verify the sanity of the returned callback table
4171 * using IsBadCodePtr */
4173 This->dp2->bDPLSPInitialized = TRUE;
4175 /* This interface is now initialized as a lobby object */
4176 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4178 /* Store the handle of the module so that we can unload it later */
4179 This->dp2->hDPLobbyProvider = hLobbyProvider;
4181 return hr;
4184 static HRESULT WINAPI DP_IF_InitializeConnection
4185 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4187 HMODULE hServiceProvider;
4188 HRESULT hr;
4189 GUID guidSP;
4190 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4191 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4193 TRACE("(%p)->(%p,0x%08lx,%u)\n", This, lpConnection, dwFlags, bAnsi );
4195 if( dwFlags != 0 )
4197 return DPERR_INVALIDFLAGS;
4200 /* Find out what the requested SP is and how large this buffer is */
4201 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4202 dwAddrSize, &guidSP );
4204 if( FAILED(hr) )
4206 ERR( "Invalid compound address?\n" );
4207 return DPERR_UNAVAILABLE;
4210 /* Load the service provider */
4211 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4213 if( hServiceProvider == 0 )
4215 ERR( "Unable to load service provider\n" );
4216 return DPERR_UNAVAILABLE;
4219 if( bIsDpSp )
4221 /* Fill in what we can of the Service Provider required information.
4222 * The rest was be done in DP_LoadSP
4224 This->dp2->spData.lpAddress = lpConnection;
4225 This->dp2->spData.dwAddressSize = dwAddrSize;
4226 This->dp2->spData.lpGuid = &guidSP;
4228 hr = DP_InitializeDPSP( This, hServiceProvider );
4230 else
4232 This->dp2->dplspData.lpAddress = lpConnection;
4234 hr = DP_InitializeDPLSP( This, hServiceProvider );
4237 if( FAILED(hr) )
4239 return hr;
4242 return DP_OK;
4245 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4246 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4248 ICOM_THIS(IDirectPlay3Impl,iface);
4250 /* This may not be externally invoked once either an SP or LP is initialized */
4251 if( This->dp2->connectionInitialized != NO_PROVIDER )
4253 return DPERR_ALREADYINITIALIZED;
4256 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4259 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4260 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4262 ICOM_THIS(IDirectPlay3Impl,iface);
4264 /* This may not be externally invoked once either an SP or LP is initialized */
4265 if( This->dp2->connectionInitialized != NO_PROVIDER )
4267 return DPERR_ALREADYINITIALIZED;
4270 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4273 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4274 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4275 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4277 ICOM_THIS(IDirectPlay2Impl,iface); /* Yes a dp 2 interface */
4278 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4281 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4282 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4283 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4285 ICOM_THIS(IDirectPlay2Impl,iface); /* Yes a dp 2 interface */
4286 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4289 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4290 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4292 ICOM_THIS(IDirectPlay3Impl,iface);
4293 FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4294 return DP_OK;
4297 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4298 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4300 ICOM_THIS(IDirectPlay3Impl,iface);
4301 FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4302 return DP_OK;
4305 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4306 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4308 ICOM_THIS(IDirectPlay3Impl,iface);
4309 FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4310 return DP_OK;
4313 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4314 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4316 ICOM_THIS(IDirectPlay3Impl,iface);
4317 FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4318 return DP_OK;
4321 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4322 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4324 ICOM_THIS(IDirectPlay3Impl,iface);
4325 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup );
4326 return DP_OK;
4329 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4330 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4332 ICOM_THIS(IDirectPlay3Impl,iface);
4333 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup );
4334 return DP_OK;
4337 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4338 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4340 ICOM_THIS(IDirectPlay3Impl,iface);
4341 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags );
4342 return DP_OK;
4345 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4346 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4348 ICOM_THIS(IDirectPlay3Impl,iface);
4349 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags );
4350 return DP_OK;
4353 static HRESULT WINAPI DP_IF_GetGroupParent
4354 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4355 BOOL bAnsi )
4357 lpGroupData lpGData;
4359 TRACE("(%p)->(0x%08lx,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4361 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4363 return DPERR_INVALIDGROUP;
4366 *lpidGroup = lpGData->dpid;
4368 return DP_OK;
4371 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4372 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4374 ICOM_THIS(IDirectPlay3Impl,iface);
4375 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4377 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4378 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4380 ICOM_THIS(IDirectPlay3Impl,iface);
4381 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4384 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4385 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4387 ICOM_THIS(IDirectPlay3Impl,iface);
4388 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4389 return DP_OK;
4392 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4393 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4395 ICOM_THIS(IDirectPlay3Impl,iface);
4396 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4397 return DP_OK;
4400 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4401 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4403 ICOM_THIS(IDirectPlay3Impl,iface);
4404 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags );
4405 return DP_OK;
4408 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4409 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4411 ICOM_THIS(IDirectPlay3Impl,iface);
4412 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags );
4413 return DP_OK;
4416 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4417 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4419 ICOM_THIS(IDirectPlay4Impl,iface);
4420 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner );
4421 return DP_OK;
4424 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4425 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4427 ICOM_THIS(IDirectPlay4Impl,iface);
4428 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner );
4429 return DP_OK;
4432 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4433 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4435 ICOM_THIS(IDirectPlay4Impl,iface);
4436 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner );
4437 return DP_OK;
4440 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4441 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4443 ICOM_THIS(IDirectPlay4Impl,iface);
4444 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner );
4445 return DP_OK;
4448 static HRESULT WINAPI DP_SendEx
4449 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4450 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4451 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4453 lpPlayerList lpPList;
4454 lpGroupData lpGData;
4455 BOOL bValidDestination = FALSE;
4457 FIXME( "(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx,0x%08lx,0x%08lx,%p,%p,%u)"
4458 ": stub\n",
4459 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4460 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4462 /* FIXME: Add parameter checking */
4463 /* FIXME: First call to this needs to aquire a message id which will be
4464 * used for multiple sends
4467 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4469 /* Verify that the message is being sent from a valid local player. The
4470 * from player may be anonymous DPID_UNKNOWN
4472 if( idFrom != DPID_UNKNOWN )
4474 if( ( lpPList = DP_FindPlayer( This, idFrom ) ) == NULL )
4476 WARN( "INFO: Invalid from player 0x%08lx\n", idFrom );
4477 return DPERR_INVALIDPLAYER;
4481 /* Verify that the message is being sent to a valid player, group or to
4482 * everyone. If it's valid, send it to those players.
4484 if( idTo == DPID_ALLPLAYERS )
4486 bValidDestination = TRUE;
4488 /* See if SP has the ability to multicast. If so, use it */
4489 if( This->dp2->spData.lpCB->SendToGroupEx )
4491 FIXME( "Use group sendex to group 0\n" );
4493 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4495 FIXME( "Use obsolete group send to group 0\n" );
4497 else /* No multicast, multiplicate */
4499 /* Send to all players we know about */
4500 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4504 if( ( !bValidDestination ) &&
4505 ( DP_FindPlayer( This, idTo ) != NULL )
4508 bValidDestination = TRUE;
4510 /* Have the service provider send this message */
4511 /* FIXME: Could optimize for local interface sends */
4512 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4513 dwTimeout, lpContext, lpdwMsgID );
4516 if( ( !bValidDestination ) &&
4517 ( ( lpGData = DP_FindAnyGroup( This, idTo ) ) != NULL )
4520 bValidDestination = TRUE;
4522 /* See if SP has the ability to multicast. If so, use it */
4523 if( This->dp2->spData.lpCB->SendToGroupEx )
4525 FIXME( "Use group sendex\n" );
4527 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4529 FIXME( "Use obsolete group send to group\n" );
4531 else /* No multicast, multiplicate */
4533 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4536 #if 0
4537 if( bExpectReply )
4539 DWORD dwWaitReturn;
4541 This->dp2->hReplyEvent = CreateEventA( NULL, FALSE, FALSE, NULL );
4543 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4544 if( dwWaitReturn != WAIT_OBJECT_0 )
4546 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4549 #endif
4552 if( !bValidDestination )
4554 return DPERR_INVALIDPLAYER;
4556 else
4558 /* FIXME: Should return what the send returned */
4559 return DP_OK;
4564 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4565 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4566 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4567 LPVOID lpContext, LPDWORD lpdwMsgID )
4569 ICOM_THIS(IDirectPlay2Impl,iface); /* yes downcast to 2 */
4570 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4571 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4574 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4575 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4576 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4577 LPVOID lpContext, LPDWORD lpdwMsgID )
4579 ICOM_THIS(IDirectPlay2Impl,iface); /* yes downcast to 2 */
4580 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4581 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4584 static HRESULT WINAPI DP_SP_SendEx
4585 ( IDirectPlay2Impl* This, DWORD dwFlags,
4586 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4587 LPVOID lpContext, LPDWORD lpdwMsgID )
4589 LPDPMSG lpMElem;
4591 FIXME( ": stub\n" );
4593 /* FIXME: This queuing should only be for async messages */
4595 lpMElem = (LPDPMSG)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4596 sizeof( *lpMElem ) );
4597 lpMElem->msg = (DPMSG_GENERIC*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4598 dwDataSize );
4600 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4602 /* FIXME: Need to queue based on priority */
4603 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4605 return DP_OK;
4608 static HRESULT WINAPI DP_IF_GetMessageQueue
4609 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4610 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4612 HRESULT hr = DP_OK;
4614 FIXME( "(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,%p,%u): semi stub\n",
4615 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4617 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4618 /* FIXME: What about sends which are not immediate? */
4620 if( This->dp2->spData.lpCB->GetMessageQueue )
4622 DPSP_GETMESSAGEQUEUEDATA data;
4624 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4626 /* FIXME: None of this is documented :( */
4628 data.lpISP = This->dp2->spData.lpISP;
4629 data.dwFlags = dwFlags;
4630 data.idFrom = idFrom;
4631 data.idTo = idTo;
4632 data.lpdwNumMsgs = lpdwNumMsgs;
4633 data.lpdwNumBytes = lpdwNumBytes;
4635 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4637 else
4639 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4642 return hr;
4645 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4646 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4647 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4649 ICOM_THIS(IDirectPlay4Impl,iface);
4650 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4651 lpdwNumBytes, TRUE );
4654 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4655 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4656 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4658 ICOM_THIS(IDirectPlay4Impl,iface);
4659 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4660 lpdwNumBytes, FALSE );
4663 static HRESULT WINAPI DP_IF_CancelMessage
4664 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4665 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4667 HRESULT hr = DP_OK;
4669 FIXME( "(%p)->(0x%08lx,0x%08lx,%u): semi stub\n",
4670 This, dwMsgID, dwFlags, bAnsi );
4672 if( This->dp2->spData.lpCB->Cancel )
4674 DPSP_CANCELDATA data;
4676 TRACE( "Calling SP Cancel\n" );
4678 /* FIXME: Undocumented callback */
4680 data.lpISP = This->dp2->spData.lpISP;
4681 data.dwFlags = dwFlags;
4682 data.lprglpvSPMsgID = NULL;
4683 data.cSPMsgID = dwMsgID;
4684 data.dwMinPriority = dwMinPriority;
4685 data.dwMaxPriority = dwMaxPriority;
4687 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4689 else
4691 FIXME( "SP doesn't implement Cancel\n" );
4694 return hr;
4697 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4698 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4700 ICOM_THIS(IDirectPlay4Impl,iface);
4702 if( dwFlags != 0 )
4704 return DPERR_INVALIDFLAGS;
4707 if( dwMsgID == 0 )
4709 dwFlags |= DPCANCELSEND_ALL;
4712 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4715 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4716 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4718 ICOM_THIS(IDirectPlay4Impl,iface);
4720 if( dwFlags != 0 )
4722 return DPERR_INVALIDFLAGS;
4725 if( dwMsgID == 0 )
4727 dwFlags |= DPCANCELSEND_ALL;
4730 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4733 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4734 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4735 DWORD dwFlags )
4737 ICOM_THIS(IDirectPlay4Impl,iface);
4739 if( dwFlags != 0 )
4741 return DPERR_INVALIDFLAGS;
4744 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4745 dwMaxPriority, TRUE );
4748 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4749 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4750 DWORD dwFlags )
4752 ICOM_THIS(IDirectPlay4Impl,iface);
4754 if( dwFlags != 0 )
4756 return DPERR_INVALIDFLAGS;
4759 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4760 dwMaxPriority, FALSE );
4763 /* Note: Hack so we can reuse the old functions without compiler warnings */
4764 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4765 # define XCAST(fun) (typeof(directPlay2WVT.fun))
4766 #else
4767 # define XCAST(fun) (void*)
4768 #endif
4770 static ICOM_VTABLE(IDirectPlay2) directPlay2WVT =
4772 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4773 XCAST(QueryInterface)DP_QueryInterface,
4774 XCAST(AddRef)DP_AddRef,
4775 XCAST(Release)DP_Release,
4777 DirectPlay2WImpl_AddPlayerToGroup,
4778 DirectPlay2WImpl_Close,
4779 DirectPlay2WImpl_CreateGroup,
4780 DirectPlay2WImpl_CreatePlayer,
4781 DirectPlay2WImpl_DeletePlayerFromGroup,
4782 DirectPlay2WImpl_DestroyGroup,
4783 DirectPlay2WImpl_DestroyPlayer,
4784 DirectPlay2WImpl_EnumGroupPlayers,
4785 DirectPlay2WImpl_EnumGroups,
4786 DirectPlay2WImpl_EnumPlayers,
4787 DirectPlay2WImpl_EnumSessions,
4788 DirectPlay2WImpl_GetCaps,
4789 DirectPlay2WImpl_GetGroupData,
4790 DirectPlay2WImpl_GetGroupName,
4791 DirectPlay2WImpl_GetMessageCount,
4792 DirectPlay2WImpl_GetPlayerAddress,
4793 DirectPlay2WImpl_GetPlayerCaps,
4794 DirectPlay2WImpl_GetPlayerData,
4795 DirectPlay2WImpl_GetPlayerName,
4796 DirectPlay2WImpl_GetSessionDesc,
4797 DirectPlay2WImpl_Initialize,
4798 DirectPlay2WImpl_Open,
4799 DirectPlay2WImpl_Receive,
4800 DirectPlay2WImpl_Send,
4801 DirectPlay2WImpl_SetGroupData,
4802 DirectPlay2WImpl_SetGroupName,
4803 DirectPlay2WImpl_SetPlayerData,
4804 DirectPlay2WImpl_SetPlayerName,
4805 DirectPlay2WImpl_SetSessionDesc
4807 #undef XCAST
4809 /* Note: Hack so we can reuse the old functions without compiler warnings */
4810 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4811 # define XCAST(fun) (typeof(directPlay2AVT.fun))
4812 #else
4813 # define XCAST(fun) (void*)
4814 #endif
4816 static ICOM_VTABLE(IDirectPlay2) directPlay2AVT =
4818 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4819 XCAST(QueryInterface)DP_QueryInterface,
4820 XCAST(AddRef)DP_AddRef,
4821 XCAST(Release)DP_Release,
4823 DirectPlay2AImpl_AddPlayerToGroup,
4824 DirectPlay2AImpl_Close,
4825 DirectPlay2AImpl_CreateGroup,
4826 DirectPlay2AImpl_CreatePlayer,
4827 DirectPlay2AImpl_DeletePlayerFromGroup,
4828 DirectPlay2AImpl_DestroyGroup,
4829 DirectPlay2AImpl_DestroyPlayer,
4830 DirectPlay2AImpl_EnumGroupPlayers,
4831 DirectPlay2AImpl_EnumGroups,
4832 DirectPlay2AImpl_EnumPlayers,
4833 DirectPlay2AImpl_EnumSessions,
4834 DirectPlay2AImpl_GetCaps,
4835 DirectPlay2AImpl_GetGroupData,
4836 DirectPlay2AImpl_GetGroupName,
4837 DirectPlay2AImpl_GetMessageCount,
4838 DirectPlay2AImpl_GetPlayerAddress,
4839 DirectPlay2AImpl_GetPlayerCaps,
4840 DirectPlay2AImpl_GetPlayerData,
4841 DirectPlay2AImpl_GetPlayerName,
4842 DirectPlay2AImpl_GetSessionDesc,
4843 DirectPlay2AImpl_Initialize,
4844 DirectPlay2AImpl_Open,
4845 DirectPlay2AImpl_Receive,
4846 DirectPlay2AImpl_Send,
4847 DirectPlay2AImpl_SetGroupData,
4848 DirectPlay2AImpl_SetGroupName,
4849 DirectPlay2AImpl_SetPlayerData,
4850 DirectPlay2AImpl_SetPlayerName,
4851 DirectPlay2AImpl_SetSessionDesc
4853 #undef XCAST
4856 /* Note: Hack so we can reuse the old functions without compiler warnings */
4857 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4858 # define XCAST(fun) (typeof(directPlay3AVT.fun))
4859 #else
4860 # define XCAST(fun) (void*)
4861 #endif
4863 static ICOM_VTABLE(IDirectPlay3) directPlay3AVT =
4865 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4866 XCAST(QueryInterface)DP_QueryInterface,
4867 XCAST(AddRef)DP_AddRef,
4868 XCAST(Release)DP_Release,
4870 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
4871 XCAST(Close)DirectPlay2AImpl_Close,
4872 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
4873 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
4874 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
4875 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
4876 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
4877 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
4878 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
4879 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
4880 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
4881 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
4882 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
4883 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
4884 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
4885 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
4886 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
4887 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
4888 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
4889 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
4890 XCAST(Initialize)DirectPlay2AImpl_Initialize,
4891 XCAST(Open)DirectPlay2AImpl_Open,
4892 XCAST(Receive)DirectPlay2AImpl_Receive,
4893 XCAST(Send)DirectPlay2AImpl_Send,
4894 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
4895 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
4896 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
4897 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
4898 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
4900 DirectPlay3AImpl_AddGroupToGroup,
4901 DirectPlay3AImpl_CreateGroupInGroup,
4902 DirectPlay3AImpl_DeleteGroupFromGroup,
4903 DirectPlay3AImpl_EnumConnections,
4904 DirectPlay3AImpl_EnumGroupsInGroup,
4905 DirectPlay3AImpl_GetGroupConnectionSettings,
4906 DirectPlay3AImpl_InitializeConnection,
4907 DirectPlay3AImpl_SecureOpen,
4908 DirectPlay3AImpl_SendChatMessage,
4909 DirectPlay3AImpl_SetGroupConnectionSettings,
4910 DirectPlay3AImpl_StartSession,
4911 DirectPlay3AImpl_GetGroupFlags,
4912 DirectPlay3AImpl_GetGroupParent,
4913 DirectPlay3AImpl_GetPlayerAccount,
4914 DirectPlay3AImpl_GetPlayerFlags
4916 #undef XCAST
4918 /* Note: Hack so we can reuse the old functions without compiler warnings */
4919 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4920 # define XCAST(fun) (typeof(directPlay3WVT.fun))
4921 #else
4922 # define XCAST(fun) (void*)
4923 #endif
4924 static ICOM_VTABLE(IDirectPlay3) directPlay3WVT =
4926 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4927 XCAST(QueryInterface)DP_QueryInterface,
4928 XCAST(AddRef)DP_AddRef,
4929 XCAST(Release)DP_Release,
4931 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
4932 XCAST(Close)DirectPlay2WImpl_Close,
4933 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
4934 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
4935 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
4936 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
4937 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
4938 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
4939 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
4940 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
4941 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
4942 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
4943 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
4944 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
4945 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
4946 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
4947 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
4948 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
4949 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
4950 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
4951 XCAST(Initialize)DirectPlay2WImpl_Initialize,
4952 XCAST(Open)DirectPlay2WImpl_Open,
4953 XCAST(Receive)DirectPlay2WImpl_Receive,
4954 XCAST(Send)DirectPlay2WImpl_Send,
4955 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
4956 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
4957 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
4958 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
4959 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
4961 DirectPlay3WImpl_AddGroupToGroup,
4962 DirectPlay3WImpl_CreateGroupInGroup,
4963 DirectPlay3WImpl_DeleteGroupFromGroup,
4964 DirectPlay3WImpl_EnumConnections,
4965 DirectPlay3WImpl_EnumGroupsInGroup,
4966 DirectPlay3WImpl_GetGroupConnectionSettings,
4967 DirectPlay3WImpl_InitializeConnection,
4968 DirectPlay3WImpl_SecureOpen,
4969 DirectPlay3WImpl_SendChatMessage,
4970 DirectPlay3WImpl_SetGroupConnectionSettings,
4971 DirectPlay3WImpl_StartSession,
4972 DirectPlay3WImpl_GetGroupFlags,
4973 DirectPlay3WImpl_GetGroupParent,
4974 DirectPlay3WImpl_GetPlayerAccount,
4975 DirectPlay3WImpl_GetPlayerFlags
4977 #undef XCAST
4979 /* Note: Hack so we can reuse the old functions without compiler warnings */
4980 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4981 # define XCAST(fun) (typeof(directPlay4WVT.fun))
4982 #else
4983 # define XCAST(fun) (void*)
4984 #endif
4985 static ICOM_VTABLE(IDirectPlay4) directPlay4WVT =
4987 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4988 XCAST(QueryInterface)DP_QueryInterface,
4989 XCAST(AddRef)DP_AddRef,
4990 XCAST(Release)DP_Release,
4992 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
4993 XCAST(Close)DirectPlay2WImpl_Close,
4994 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
4995 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
4996 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
4997 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
4998 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
4999 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5000 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5001 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5002 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5003 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5004 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5005 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5006 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5007 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5008 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5009 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5010 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5011 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5012 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5013 XCAST(Open)DirectPlay2WImpl_Open,
5014 XCAST(Receive)DirectPlay2WImpl_Receive,
5015 XCAST(Send)DirectPlay2WImpl_Send,
5016 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5017 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5018 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5019 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5020 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5022 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5023 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5024 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5025 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5026 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5027 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5028 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5029 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5030 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5031 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5032 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5033 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5034 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5035 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5036 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5038 DirectPlay4WImpl_GetGroupOwner,
5039 DirectPlay4WImpl_SetGroupOwner,
5040 DirectPlay4WImpl_SendEx,
5041 DirectPlay4WImpl_GetMessageQueue,
5042 DirectPlay4WImpl_CancelMessage,
5043 DirectPlay4WImpl_CancelPriority
5045 #undef XCAST
5048 /* Note: Hack so we can reuse the old functions without compiler warnings */
5049 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5050 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5051 #else
5052 # define XCAST(fun) (void*)
5053 #endif
5054 static ICOM_VTABLE(IDirectPlay4) directPlay4AVT =
5056 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
5057 XCAST(QueryInterface)DP_QueryInterface,
5058 XCAST(AddRef)DP_AddRef,
5059 XCAST(Release)DP_Release,
5061 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5062 XCAST(Close)DirectPlay2AImpl_Close,
5063 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5064 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5065 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5066 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5067 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5068 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5069 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5070 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5071 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5072 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5073 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5074 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5075 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5076 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5077 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5078 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5079 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5080 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5081 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5082 XCAST(Open)DirectPlay2AImpl_Open,
5083 XCAST(Receive)DirectPlay2AImpl_Receive,
5084 XCAST(Send)DirectPlay2AImpl_Send,
5085 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5086 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5087 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5088 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5089 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5091 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5092 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5093 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5094 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5095 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5096 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5097 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5098 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5099 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5100 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5101 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5102 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5103 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5104 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5105 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5107 DirectPlay4AImpl_GetGroupOwner,
5108 DirectPlay4AImpl_SetGroupOwner,
5109 DirectPlay4AImpl_SendEx,
5110 DirectPlay4AImpl_GetMessageQueue,
5111 DirectPlay4AImpl_CancelMessage,
5112 DirectPlay4AImpl_CancelPriority
5114 #undef XCAST
5116 extern
5117 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5118 DPID idPlayer,
5119 LPVOID* lplpData )
5121 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5123 if( lpPlayer == NULL )
5125 return DPERR_INVALIDPLAYER;
5128 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5130 return DP_OK;
5133 extern
5134 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5135 DPID idPlayer,
5136 LPVOID lpData )
5138 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5140 if( lpPlayer == NULL )
5142 return DPERR_INVALIDPLAYER;
5145 lpPlayer->lpPData->lpSPPlayerData = lpData;
5147 return DP_OK;
5150 /***************************************************************************
5151 * DirectPlayEnumerate [DPLAYX.9]
5152 * DirectPlayEnumerateA [DPLAYX.2]
5154 * The pointer to the structure lpContext will be filled with the
5155 * appropriate data for each service offered by the OS. These services are
5156 * not necessarily available on this particular machine but are defined
5157 * as simple service providers under the "Service Providers" registry key.
5158 * This structure is then passed to lpEnumCallback for each of the different
5159 * services.
5161 * This API is useful only for applications written using DirectX3 or
5162 * worse. It is superceeded by IDirectPlay3::EnumConnections which also
5163 * gives information on the actual connections.
5165 * defn of a service provider:
5166 * A dynamic-link library used by DirectPlay to communicate over a network.
5167 * The service provider contains all the network-specific code required
5168 * to send and receive messages. Online services and network operators can
5169 * supply service providers to use specialized hardware, protocols, communications
5170 * media, and network resources.
5172 * TODO: Allocate string buffer space from the heap (length from reg)
5173 * Pass real device driver numbers...
5174 * Get the GUID properly...
5176 HRESULT WINAPI DirectPlayEnumerateA( LPDPENUMDPCALLBACKA lpEnumCallback,
5177 LPVOID lpContext )
5180 HKEY hkResult;
5181 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
5182 DWORD dwIndex;
5183 DWORD sizeOfSubKeyName=50;
5184 char subKeyName[51];
5185 FILETIME filetime;
5187 TRACE(": lpEnumCallback=%p lpContext=%p\n", lpEnumCallback, lpContext );
5189 if( !lpEnumCallback || !*lpEnumCallback )
5191 return DPERR_INVALIDPARAMS;
5194 /* Need to loop over the service providers in the registry */
5195 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
5196 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
5198 /* Hmmm. Does this mean that there are no service providers? */
5199 ERR(": no service providers?\n");
5200 return DP_OK;
5203 /* Traverse all the service providers we have available */
5204 for( dwIndex=0;
5205 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5206 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
5207 ++dwIndex, sizeOfSubKeyName=50 )
5209 LPSTR majVerDataSubKey = "dwReserved1";
5210 LPSTR minVerDataSubKey = "dwReserved2";
5211 LPSTR guidDataSubKey = "Guid";
5212 HKEY hkServiceProvider;
5213 GUID serviceProviderGUID;
5214 DWORD returnTypeGUID, returnTypeReserved, sizeOfReturnBuffer = 50;
5215 char returnBuffer[51];
5216 WCHAR buff[51];
5217 DWORD majVersionNum , minVersionNum = 0;
5219 TRACE(" this time through: %s\n", subKeyName );
5221 /* Get a handle for this particular service provider */
5222 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
5223 &hkServiceProvider ) != ERROR_SUCCESS )
5225 ERR(": what the heck is going on?\n" );
5226 continue;
5229 /* Get the GUID, Device major number and device minor number
5230 * from the registry.
5232 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
5233 NULL, &returnTypeGUID, returnBuffer,
5234 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
5236 ERR(": missing GUID registry data members\n" );
5237 continue;
5240 /* FIXME: Check return types to ensure we're interpreting data right */
5241 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
5242 CLSIDFromString( (LPCOLESTR)buff, &serviceProviderGUID );
5244 /* FIXME: Need to know which of dwReserved1 and dwReserved2 are maj and min */
5246 sizeOfReturnBuffer = 50;
5247 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
5248 NULL, &returnTypeReserved, returnBuffer,
5249 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
5251 ERR(": missing dwReserved1 registry data members\n") ;
5252 continue;
5255 majVersionNum = GET_DWORD( returnBuffer );
5257 sizeOfReturnBuffer = 50;
5258 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
5259 NULL, &returnTypeReserved, returnBuffer,
5260 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
5262 ERR(": missing dwReserved2 registry data members\n") ;
5263 continue;
5266 minVersionNum = GET_DWORD( returnBuffer );
5269 /* The enumeration will return FALSE if we are not to continue */
5270 if( !lpEnumCallback( &serviceProviderGUID , subKeyName,
5271 majVersionNum, minVersionNum, lpContext ) )
5273 WARN("lpEnumCallback returning FALSE\n" );
5274 break;
5278 return DP_OK;
5282 /***************************************************************************
5283 * DirectPlayEnumerateW [DPLAYX.3]
5286 HRESULT WINAPI DirectPlayEnumerateW( LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5289 FIXME(":stub\n");
5291 return DPERR_OUTOFMEMORY;
5295 typedef struct tagCreateEnum
5297 LPVOID lpConn;
5298 LPCGUID lpGuid;
5299 } CreateEnumData, *lpCreateEnumData;
5301 /* Find and copy the matching connection for the SP guid */
5302 static BOOL CALLBACK cbDPCreateEnumConnections(
5303 LPCGUID lpguidSP,
5304 LPVOID lpConnection,
5305 DWORD dwConnectionSize,
5306 LPCDPNAME lpName,
5307 DWORD dwFlags,
5308 LPVOID lpContext)
5310 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5312 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5314 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5316 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5317 dwConnectionSize );
5318 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5320 /* Found the record that we were looking for */
5321 return FALSE;
5324 /* Haven't found what were looking for yet */
5325 return TRUE;
5329 /***************************************************************************
5330 * DirectPlayCreate [DPLAYX.1]
5333 HRESULT WINAPI DirectPlayCreate
5334 ( LPGUID lpGUID, LPDIRECTPLAY2 *lplpDP, IUnknown *pUnk)
5336 HRESULT hr;
5337 LPDIRECTPLAY3A lpDP3A;
5338 CreateEnumData cbData;
5340 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5342 if( pUnk != NULL )
5344 return CLASS_E_NOAGGREGATION;
5347 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5348 give them an IDirectPlay2A object and hope that doesn't cause problems */
5349 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5351 return DPERR_UNAVAILABLE;
5354 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5356 /* The GUID_NULL means don't bind a service provider. Just return the
5357 interface as is */
5358 return DP_OK;
5361 /* Bind the desired service provider since lpGUID is non NULL */
5362 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5364 /* We're going to use a DP3 interface */
5365 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5366 (LPVOID*)&lpDP3A );
5367 if( FAILED(hr) )
5369 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5370 return hr;
5373 cbData.lpConn = NULL;
5374 cbData.lpGuid = lpGUID;
5376 /* We were given a service provider, find info about it... */
5377 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5378 &cbData, DPCONNECTION_DIRECTPLAY );
5379 if( ( FAILED(hr) ) ||
5380 ( cbData.lpConn == NULL )
5383 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5384 IDirectPlayX_Release( lpDP3A );
5385 return DPERR_UNAVAILABLE;
5388 /* Initialize the service provider */
5389 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5390 if( FAILED(hr) )
5392 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5393 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5394 IDirectPlayX_Release( lpDP3A );
5395 return hr;
5398 /* Release our version of the interface now that we're done with it */
5399 IDirectPlayX_Release( lpDP3A );
5400 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5402 return DP_OK;