kernel32: GlobalMemoryStatusEx: return the size of physical memory + swapsize in...
[wine] / dlls / dplayx / dplay.c
1 /* Direct Play 2,3,4 Implementation
2  *
3  * Copyright 1998,1999,2000,2001 - Peter Hunnisett
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include "config.h"
21 #include "wine/port.h"
22
23 #include <stdarg.h>
24 #include <string.h>
25
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winerror.h"
30 #include "winbase.h"
31 #include "winnt.h"
32 #include "winreg.h"
33 #include "winnls.h"
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
36
37 #include "dpinit.h"
38 #include "dplayx_global.h"
39 #include "name_server.h"
40 #include "dplayx_queue.h"
41 #include "dplaysp.h"
42 #include "dplay_global.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
45
46 /* FIXME: Should this be externed? */
47 extern HRESULT DPL_CreateCompoundAddress
48 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
49   LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
50
51
52 /* Local function prototypes */
53 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
54 static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
55                                      LPDPNAME lpName, DWORD dwFlags,
56                                      HANDLE hEvent, BOOL bAnsi );
57 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi );
58 static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
59                               LPVOID lpData, DWORD dwDataSize );
60
61 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, LPDPID lpid,
62                                    LPDPNAME lpName, DWORD dwFlags,
63                                    DPID idParent, BOOL bAnsi );
64 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
65                              LPVOID lpData, DWORD dwDataSize );
66 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
67 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
68 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
69                                                   DWORD dwPlayerType,
70                                                   LPCDPNAME lpName,
71                                                   DWORD dwFlags,
72                                                   LPVOID lpContext );
73 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
74 static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
75                                             LPCDPNAME lpName, DWORD dwFlags,
76                                             LPVOID lpContext );
77 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
78
79 /* Forward declarations of virtual tables */
80 static const IDirectPlay2Vtbl directPlay2AVT;
81 static const IDirectPlay3Vtbl directPlay3AVT;
82 static const IDirectPlay4Vtbl directPlay4AVT;
83
84 static const IDirectPlay2Vtbl directPlay2WVT;
85 static const IDirectPlay3Vtbl directPlay3WVT;
86 static const IDirectPlay4Vtbl directPlay4WVT;
87
88 /* Helper methods for player/group interfaces */
89 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
90           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
91             DPID idPlayer, BOOL bAnsi );
92 static HRESULT WINAPI DP_IF_CreatePlayer
93           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
94             LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
95             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
96 static HRESULT WINAPI DP_IF_DestroyGroup
97           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
98 static HRESULT WINAPI DP_IF_DestroyPlayer
99           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
100 static HRESULT WINAPI DP_IF_EnumGroupPlayers
101           ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
102             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
103             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
104 static HRESULT WINAPI DP_IF_EnumGroups
105           ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
106             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
107             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
108 static HRESULT WINAPI DP_IF_EnumPlayers
109           ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
110             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
111             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
112 static HRESULT WINAPI DP_IF_GetGroupData
113           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
114             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
115 static HRESULT WINAPI DP_IF_GetGroupName
116           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
117             LPDWORD lpdwDataSize, BOOL bAnsi );
118 static HRESULT WINAPI DP_IF_GetPlayerData
119           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
120             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
121 static HRESULT WINAPI DP_IF_GetPlayerName
122           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
123             LPDWORD lpdwDataSize, BOOL bAnsi );
124 static HRESULT WINAPI DP_IF_SetGroupName
125           ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
126             DWORD dwFlags, BOOL bAnsi );
127 static HRESULT WINAPI DP_IF_SetPlayerData
128           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
129             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
130 static HRESULT WINAPI DP_IF_SetPlayerName
131           ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
132             DWORD dwFlags, BOOL bAnsi );
133 static HRESULT WINAPI DP_IF_AddGroupToGroup
134           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
135 static HRESULT WINAPI DP_IF_CreateGroup
136           ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
137             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
138             DWORD dwFlags, BOOL bAnsi );
139 static HRESULT WINAPI DP_IF_CreateGroupInGroup
140           ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
141             LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
142             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
143 static HRESULT WINAPI DP_IF_AddPlayerToGroup
144           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
145             DPID idPlayer, BOOL bAnsi );
146 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
147           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
148 static HRESULT WINAPI DP_SetSessionDesc
149           ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
150             DWORD dwFlags, BOOL bInitial, BOOL bAnsi  );
151 static HRESULT WINAPI DP_SecureOpen
152           ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
153             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
154             BOOL bAnsi );
155 static HRESULT WINAPI DP_SendEx
156           ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
157             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
158             LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
159 static HRESULT WINAPI DP_IF_Receive
160           ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
161             DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
162 static HRESULT WINAPI DP_IF_GetMessageQueue
163           ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
164             LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
165 static HRESULT WINAPI DP_SP_SendEx
166           ( IDirectPlay2Impl* This, DWORD dwFlags,
167             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
168             LPVOID lpContext, LPDWORD lpdwMsgID );
169 static HRESULT WINAPI DP_IF_SetGroupData
170           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
171             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
172 static HRESULT WINAPI DP_IF_GetPlayerCaps
173           ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
174             DWORD dwFlags );
175 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
176 static HRESULT WINAPI DP_IF_CancelMessage
177           ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
178             DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
179 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
180           ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
181             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
182             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
183 static HRESULT WINAPI DP_IF_GetGroupParent
184           ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
185             BOOL bAnsi );
186 static HRESULT WINAPI DP_IF_GetCaps
187           ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
188 static HRESULT WINAPI DP_IF_EnumSessions
189           ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
190             LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
191             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
192 static HRESULT WINAPI DP_IF_InitializeConnection
193           ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
194 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
195     LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
196     DWORD dwFlags, LPVOID lpContext );
197 static BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
198                                            LPDWORD lpdwBufSize );
199
200
201
202 static inline DPID DP_NextObjectId(void);
203 static DPID DP_GetRemoteNextObjectId(void);
204
205
206 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
207                                 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
208
209
210 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
211 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
212 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
213
214
215
216
217
218
219 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
220 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
221                                                  we don't have to change much */
222 #define DPID_NAME_SERVER 0x19a9d65b  /* Don't ask me why */
223
224 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
225 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
226
227 /* Strip out all dwFlags values for CREATEPLAYER msg */
228 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
229
230 static LONG kludgePlayerGroupId = 1000;
231
232 /* ------------------------------------------------------------------ */
233
234
235 static BOOL DP_CreateIUnknown( LPVOID lpDP )
236 {
237   IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
238
239   This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
240   if ( This->unk == NULL )
241   {
242     return FALSE;
243   }
244
245   InitializeCriticalSection( &This->unk->DP_lock );
246   This->unk->DP_lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlay2AImpl*->DirectPlayIUnknownData*->DP_lock");
247
248   return TRUE;
249 }
250
251 static BOOL DP_DestroyIUnknown( LPVOID lpDP )
252 {
253   IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
254
255   This->unk->DP_lock.DebugInfo->Spare[0] = 0;
256   DeleteCriticalSection( &This->unk->DP_lock );
257   HeapFree( GetProcessHeap(), 0, This->unk );
258
259   return TRUE;
260 }
261
262 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
263 {
264   IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
265
266   This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
267   if ( This->dp2 == NULL )
268   {
269     return FALSE;
270   }
271
272   This->dp2->bConnectionOpen = FALSE;
273
274   This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
275
276   This->dp2->bHostInterface = FALSE;
277
278   DPQ_INIT(This->dp2->receiveMsgs);
279   DPQ_INIT(This->dp2->sendMsgs);
280   DPQ_INIT(This->dp2->replysExpected);
281
282   if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
283   {
284     /* FIXME: Memory leak */
285     return FALSE;
286   }
287
288   /* Provide an initial session desc with nothing in it */
289   This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
290                                         HEAP_ZERO_MEMORY,
291                                         sizeof( *This->dp2->lpSessionDesc ) );
292   if( This->dp2->lpSessionDesc == NULL )
293   {
294     /* FIXME: Memory leak */
295     return FALSE;
296   }
297   This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
298
299   /* We are emulating a dp 6 implementation */
300   This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
301
302   This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
303                                       sizeof( *This->dp2->spData.lpCB ) );
304   This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
305   This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
306
307   /* This is the pointer to the service provider */
308   if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
309                                     (LPVOID*)&This->dp2->spData.lpISP, This ) )
310     )
311   {
312     /* FIXME: Memory leak */
313     return FALSE;
314   }
315
316   /* Setup lobby provider information */
317   This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
318   This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
319                                          sizeof( *This->dp2->dplspData.lpCB ) );
320   This->dp2->dplspData.lpCB->dwSize = sizeof(  *This->dp2->dplspData.lpCB );
321
322   if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
323                                      (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
324     )
325   {
326     /* FIXME: Memory leak */
327     return FALSE;
328   }
329
330   return TRUE;
331 }
332
333 /* Definition of the global function in dplayx_queue.h. #
334  * FIXME: Would it be better to have a dplayx_queue.c for this function? */
335 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
336 {
337   HeapFree( GetProcessHeap(), 0, elem );
338 }
339
340 /* Function to delete the list of groups with this interface. Needs to
341  * delete the group and player lists associated with this group as well
342  * as the group data associated with this group. It should not delete
343  * player data as that is shared with the top player list and will be
344  * deleted with that.
345  */
346 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList );
347 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList )
348 {
349   DPQ_DELETEQ( elem->lpGData->groups, groups,
350                lpGroupList, cbDeleteElemFromHeap );
351   DPQ_DELETEQ( elem->lpGData->players, players,
352                lpPlayerList, cbDeleteElemFromHeap );
353   HeapFree( GetProcessHeap(), 0, elem->lpGData );
354   HeapFree( GetProcessHeap(), 0, elem );
355 }
356
357 /* Function to delete the list of players with this interface. Needs to
358  * delete the player data for all players as well.
359  */
360 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList );
361 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList )
362 {
363   HeapFree( GetProcessHeap(), 0, elem->lpPData );
364   HeapFree( GetProcessHeap(), 0, elem );
365 }
366
367 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
368 {
369   IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
370
371   if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
372   {
373     TerminateThread( This->dp2->hEnumSessionThread, 0 );
374     CloseHandle( This->dp2->hEnumSessionThread );
375   }
376
377   /* Finish with the SP - have it shutdown */
378   if( This->dp2->spData.lpCB->ShutdownEx )
379   {
380     DPSP_SHUTDOWNDATA data;
381
382     TRACE( "Calling SP ShutdownEx\n" );
383
384     data.lpISP = This->dp2->spData.lpISP;
385
386     (*This->dp2->spData.lpCB->ShutdownEx)( &data );
387   }
388   else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
389   {
390     TRACE( "Calling obsolete SP Shutdown\n" );
391     (*This->dp2->spData.lpCB->Shutdown)();
392   }
393
394   /* Unload the SP (if it exists) */
395   if( This->dp2->hServiceProvider != 0 )
396   {
397     FreeLibrary( This->dp2->hServiceProvider );
398   }
399
400   /* Unload the Lobby Provider (if it exists) */
401   if( This->dp2->hDPLobbyProvider != 0 )
402   {
403     FreeLibrary( This->dp2->hDPLobbyProvider );
404   }
405
406 #if 0
407   DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
408   DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem );
409 #endif
410
411   /* FIXME: Need to delete receive and send msgs queue contents */
412
413   NS_DeleteSessionCache( This->dp2->lpNameServerData );
414
415   HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
416
417   IDirectPlaySP_Release( This->dp2->spData.lpISP );
418
419   /* Delete the contents */
420   HeapFree( GetProcessHeap(), 0, This->dp2 );
421
422   return TRUE;
423 }
424
425 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
426 {
427   IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
428
429   This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
430   if ( This->dp3 == NULL )
431   {
432     return FALSE;
433   }
434
435   return TRUE;
436 }
437
438 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
439 {
440   IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
441
442   /* Delete the contents */
443   HeapFree( GetProcessHeap(), 0, This->dp3 );
444
445   return TRUE;
446 }
447
448 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
449 {
450   IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)lpDP;
451
452   This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
453   if ( This->dp4 == NULL )
454   {
455     return FALSE;
456   }
457
458   return TRUE;
459 }
460
461 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
462 {
463   IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
464
465   /* Delete the contents */
466   HeapFree( GetProcessHeap(), 0, This->dp4 );
467
468   return TRUE;
469 }
470
471
472 /* Create a new interface */
473 extern
474 HRESULT DP_CreateInterface
475          ( REFIID riid, LPVOID* ppvObj )
476 {
477   TRACE( " for %s\n", debugstr_guid( riid ) );
478
479   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
480                        sizeof( IDirectPlay2Impl ) );
481
482   if( *ppvObj == NULL )
483   {
484     return DPERR_OUTOFMEMORY;
485   }
486
487   if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
488   {
489     IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
490     This->lpVtbl = &directPlay2WVT;
491   }
492   else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
493   {
494     IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
495     This->lpVtbl = &directPlay2AVT;
496   }
497   else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
498   {
499     IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
500     This->lpVtbl = &directPlay3WVT;
501   }
502   else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
503   {
504     IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
505     This->lpVtbl = &directPlay3AVT;
506   }
507   else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
508   {
509     IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
510     This->lpVtbl = &directPlay4WVT;
511   }
512   else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
513   {
514     IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
515     This->lpVtbl = &directPlay4AVT;
516   }
517   else
518   {
519     /* Unsupported interface */
520     HeapFree( GetProcessHeap(), 0, *ppvObj );
521     *ppvObj = NULL;
522
523     return E_NOINTERFACE;
524   }
525
526   /* Initialize it */
527   if ( DP_CreateIUnknown( *ppvObj ) &&
528        DP_CreateDirectPlay2( *ppvObj ) &&
529        DP_CreateDirectPlay3( *ppvObj ) &&
530        DP_CreateDirectPlay4( *ppvObj )
531      )
532   {
533     IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
534
535     return S_OK;
536   }
537
538   /* Initialize failed, destroy it */
539   DP_DestroyDirectPlay4( *ppvObj );
540   DP_DestroyDirectPlay3( *ppvObj );
541   DP_DestroyDirectPlay2( *ppvObj );
542   DP_DestroyIUnknown( *ppvObj );
543
544   HeapFree( GetProcessHeap(), 0, *ppvObj );
545
546   *ppvObj = NULL;
547   return DPERR_NOMEMORY;
548 }
549
550
551 /* Direct Play methods */
552
553 /* Shared between all dplay types */
554 static HRESULT WINAPI DP_QueryInterface
555          ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
556 {
557   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
558   TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
559
560   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
561                        sizeof( *This ) );
562
563   if( *ppvObj == NULL )
564   {
565     return DPERR_OUTOFMEMORY;
566   }
567
568   CopyMemory( *ppvObj, This, sizeof( *This )  );
569   (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
570
571   if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
572   {
573     IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
574     This->lpVtbl = &directPlay2WVT;
575   }
576   else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
577   {
578     IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
579     This->lpVtbl = &directPlay2AVT;
580   }
581   else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
582   {
583     IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
584     This->lpVtbl = &directPlay3WVT;
585   }
586   else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
587   {
588     IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
589     This->lpVtbl = &directPlay3AVT;
590   }
591   else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
592   {
593     IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
594     This->lpVtbl = &directPlay4WVT;
595   }
596   else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
597   {
598     IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
599     This->lpVtbl = &directPlay4AVT;
600   }
601   else
602   {
603     /* Unsupported interface */
604     HeapFree( GetProcessHeap(), 0, *ppvObj );
605     *ppvObj = NULL;
606
607     return E_NOINTERFACE;
608   }
609
610   IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
611
612   return S_OK;
613 }
614
615 /* Shared between all dplay types */
616 static ULONG WINAPI DP_AddRef
617          ( LPDIRECTPLAY3 iface )
618 {
619   ULONG ulInterfaceRefCount, ulObjRefCount;
620   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
621
622   ulObjRefCount       = InterlockedIncrement( &This->unk->ulObjRef );
623   ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
624
625   TRACE( "ref count incremented to %u:%u for %p\n",
626          ulInterfaceRefCount, ulObjRefCount, This );
627
628   return ulObjRefCount;
629 }
630
631 static ULONG WINAPI DP_Release
632 ( LPDIRECTPLAY3 iface )
633 {
634   ULONG ulInterfaceRefCount, ulObjRefCount;
635
636   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
637
638   ulObjRefCount       = InterlockedDecrement( &This->unk->ulObjRef );
639   ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
640
641   TRACE( "ref count decremented to %u:%u for %p\n",
642          ulInterfaceRefCount, ulObjRefCount, This );
643
644   /* Deallocate if this is the last reference to the object */
645   if( ulObjRefCount == 0 )
646   {
647      /* If we're destroying the object, this must be the last ref
648         of the last interface */
649      DP_DestroyDirectPlay4( This );
650      DP_DestroyDirectPlay3( This );
651      DP_DestroyDirectPlay2( This );
652      DP_DestroyIUnknown( This );
653   }
654
655   /* Deallocate the interface */
656   if( ulInterfaceRefCount == 0 )
657   {
658     HeapFree( GetProcessHeap(), 0, This );
659   }
660
661   return ulObjRefCount;
662 }
663
664 static inline DPID DP_NextObjectId(void)
665 {
666   return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
667 }
668
669 /* *lplpReply will be non NULL iff there is something to reply */
670 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
671                           DWORD  dwMessageBodySize, LPCVOID lpcMessageHeader,
672                           WORD wCommandId, WORD wVersion,
673                           LPVOID* lplpReply, LPDWORD lpdwMsgSize )
674 {
675   TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
676          This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
677          wVersion );
678
679   switch( wCommandId )
680   {
681     /* Name server needs to handle this request */
682     case DPMSGCMD_ENUMSESSIONSREQUEST:
683     {
684       /* Reply expected */
685       NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
686
687       break;
688     }
689
690     /* Name server needs to handle this request */
691     case DPMSGCMD_ENUMSESSIONSREPLY:
692     {
693       /* No reply expected */
694       NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
695                                         This->dp2->spData.dwSPHeaderSize,
696                                         lpcMessageBody,
697                                         This->dp2->lpNameServerData );
698       break;
699     }
700
701     case DPMSGCMD_REQUESTNEWPLAYERID:
702     {
703       LPCDPMSG_REQUESTNEWPLAYERID lpcMsg =
704         (LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody;
705
706       LPDPMSG_NEWPLAYERIDREPLY lpReply;
707
708       *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
709
710       *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
711
712       FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
713              lpcMsg->dwFlags );
714
715       /* Setup the reply */
716       lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
717                                             This->dp2->spData.dwSPHeaderSize );
718
719       lpReply->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG;
720       lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
721       lpReply->envelope.wVersion   = DPMSGVER_DP6;
722
723       lpReply->dpidNewPlayerId = DP_NextObjectId();
724
725       TRACE( "Allocating new playerid 0x%08x from remote request\n",
726              lpReply->dpidNewPlayerId );
727
728       break;
729     }
730
731     case DPMSGCMD_GETNAMETABLEREPLY:
732     case DPMSGCMD_NEWPLAYERIDREPLY:
733     {
734
735 #if 0
736       if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
737         DebugBreak();
738 #endif
739       DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
740
741       break;
742     }
743
744 #if 1
745     case DPMSGCMD_JUSTENVELOPE:
746     {
747       TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
748       NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
749       DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
750     }
751 #endif
752
753     case DPMSGCMD_FORWARDADDPLAYER:
754     {
755 #if 0
756       DebugBreak();
757 #endif
758 #if 1
759     TRACE( "Sending message to self to get my addr\n" );
760     DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
761 #endif
762       break;
763     }
764
765     case DPMSGCMD_FORWARDADDPLAYERNACK:
766     {
767       DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
768       break;
769     }
770
771     default:
772     {
773       FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
774       DebugBreak();
775       break;
776     }
777   }
778
779   /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
780
781   return DP_OK;
782 }
783
784
785 static HRESULT WINAPI DP_IF_AddPlayerToGroup
786           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
787             DPID idPlayer, BOOL bAnsi )
788 {
789   lpGroupData  lpGData;
790   lpPlayerList lpPList;
791   lpPlayerList lpNewPList;
792
793   TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
794          This, lpMsgHdr, idGroup, idPlayer, bAnsi );
795
796   /* Find the group */
797   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
798   {
799     return DPERR_INVALIDGROUP;
800   }
801
802   /* Find the player */
803   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
804   {
805     return DPERR_INVALIDPLAYER;
806   }
807
808   /* Create a player list (ie "shortcut" ) */
809   lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
810   if( lpNewPList == NULL )
811   {
812     return DPERR_CANTADDPLAYER;
813   }
814
815   /* Add the shortcut */
816   lpPList->lpPData->uRef++;
817   lpNewPList->lpPData = lpPList->lpPData;
818
819   /* Add the player to the list of players for this group */
820   DPQ_INSERT(lpGData->players,lpNewPList,players);
821
822   /* Let the SP know that we've added a player to the group */
823   if( This->dp2->spData.lpCB->AddPlayerToGroup )
824   {
825     DPSP_ADDPLAYERTOGROUPDATA data;
826
827     TRACE( "Calling SP AddPlayerToGroup\n" );
828
829     data.idPlayer = idPlayer;
830     data.idGroup  = idGroup;
831     data.lpISP    = This->dp2->spData.lpISP;
832
833     (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
834   }
835
836   /* Inform all other peers of the addition of player to the group. If there are
837    * no peers keep this event quiet.
838    * Also, if this event was the result of another machine sending it to us,
839    * don't bother rebroadcasting it.
840    */
841   if( ( lpMsgHdr == NULL ) &&
842       This->dp2->lpSessionDesc &&
843       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
844   {
845     DPMSG_ADDPLAYERTOGROUP msg;
846     msg.dwType = DPSYS_ADDPLAYERTOGROUP;
847
848     msg.dpIdGroup  = idGroup;
849     msg.dpIdPlayer = idPlayer;
850
851     /* FIXME: Correct to just use send effectively? */
852     /* FIXME: Should size include data w/ message or just message "header" */
853     /* FIXME: Check return code */
854     DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),               0, 0, NULL, NULL, bAnsi );
855   }
856
857   return DP_OK;
858 }
859
860 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
861           ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
862 {
863   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
864   return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
865 }
866
867 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
868           ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
869 {
870   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
871   return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
872 }
873
874 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
875 {
876   HRESULT hr = DP_OK;
877
878   TRACE("(%p)->(%u)\n", This, bAnsi );
879
880   /* FIXME: Need to find a new host I assume (how?) */
881   /* FIXME: Need to destroy all local groups */
882   /* FIXME: Need to migrate all remotely visible players to the new host */
883
884   /* Invoke the SP callback to inform of session close */
885   if( This->dp2->spData.lpCB->CloseEx )
886   {
887     DPSP_CLOSEDATA data;
888
889     TRACE( "Calling SP CloseEx\n" );
890
891     data.lpISP = This->dp2->spData.lpISP;
892
893     hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
894
895   }
896   else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
897   {
898     TRACE( "Calling SP Close (obsolete interface)\n" );
899
900     hr = (*This->dp2->spData.lpCB->Close)();
901   }
902
903   return hr;
904 }
905
906 static HRESULT WINAPI DirectPlay2AImpl_Close
907           ( LPDIRECTPLAY2A iface )
908 {
909   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
910   return DP_IF_Close( This, TRUE );
911 }
912
913 static HRESULT WINAPI DirectPlay2WImpl_Close
914           ( LPDIRECTPLAY2 iface )
915 {
916   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
917   return DP_IF_Close( This, FALSE );
918 }
919
920 static
921 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, LPDPID lpid,
922                             LPDPNAME lpName, DWORD dwFlags,
923                             DPID idParent, BOOL bAnsi )
924 {
925   lpGroupData lpGData;
926
927   /* Allocate the new space and add to end of high level group list */
928   lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
929
930   if( lpGData == NULL )
931   {
932     return NULL;
933   }
934
935   DPQ_INIT(lpGData->groups);
936   DPQ_INIT(lpGData->players);
937
938   /* Set the desired player ID - no sanity checking to see if it exists */
939   lpGData->dpid = *lpid;
940
941   DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
942
943   /* FIXME: Should we check that the parent exists? */
944   lpGData->parent  = idParent;
945
946   /* FIXME: Should we validate the dwFlags? */
947   lpGData->dwFlags = dwFlags;
948
949   TRACE( "Created group id 0x%08x\n", *lpid );
950
951   return lpGData;
952 }
953
954 /* This method assumes that all links to it are already deleted */
955 static void
956 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
957 {
958   lpGroupList lpGList;
959
960   TRACE( "(%p)->(0x%08x)\n", This, dpid );
961
962   DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
963
964   if( lpGList == NULL )
965   {
966     ERR( "DPID 0x%08x not found\n", dpid );
967     return;
968   }
969
970   if( --(lpGList->lpGData->uRef) )
971   {
972     FIXME( "Why is this not the last reference to group?\n" );
973     DebugBreak();
974   }
975
976   /* Delete player */
977   DP_DeleteDPNameStruct( &lpGList->lpGData->name );
978   HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
979
980   /* Remove and Delete Player List object */
981   HeapFree( GetProcessHeap(), 0, lpGList );
982
983 }
984
985 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
986 {
987   lpGroupList lpGroups;
988
989   TRACE( "(%p)->(0x%08x)\n", This, dpid );
990
991   if( dpid == DPID_SYSTEM_GROUP )
992   {
993     return This->dp2->lpSysGroup;
994   }
995   else
996   {
997     DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
998   }
999
1000   if( lpGroups == NULL )
1001   {
1002     return NULL;
1003   }
1004
1005   return lpGroups->lpGData;
1006 }
1007
1008 static HRESULT WINAPI DP_IF_CreateGroup
1009           ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
1010             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
1011             DWORD dwFlags, BOOL bAnsi )
1012 {
1013   lpGroupData lpGData;
1014
1015   TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1016          This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
1017          dwFlags, bAnsi );
1018
1019   /* If the name is not specified, we must provide one */
1020   if( DPID_UNKNOWN == *lpidGroup )
1021   {
1022     /* If we are the name server, we decide on the group ids. If not, we
1023      * must ask for one before attempting a creation.
1024      */
1025     if( This->dp2->bHostInterface )
1026     {
1027       *lpidGroup = DP_NextObjectId();
1028     }
1029     else
1030     {
1031       *lpidGroup = DP_GetRemoteNextObjectId();
1032     }
1033   }
1034
1035   lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1036                             DPID_NOPARENT_GROUP, bAnsi );
1037
1038   if( lpGData == NULL )
1039   {
1040     return DPERR_CANTADDPLAYER; /* yes player not group */
1041   }
1042
1043   if( DPID_SYSTEM_GROUP == *lpidGroup )
1044   {
1045     This->dp2->lpSysGroup = lpGData;
1046     TRACE( "Inserting system group\n" );
1047   }
1048   else
1049   {
1050     /* Insert into the system group */
1051     lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1052     lpGroup->lpGData = lpGData;
1053
1054     DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1055   }
1056
1057   /* Something is now referencing this data */
1058   lpGData->uRef++;
1059
1060   /* Set all the important stuff for the group */
1061   DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1062
1063   /* FIXME: We should only create the system group if GetCaps returns
1064    *        DPCAPS_GROUPOPTIMIZED.
1065    */
1066
1067   /* Let the SP know that we've created this group */
1068   if( This->dp2->spData.lpCB->CreateGroup )
1069   {
1070     DPSP_CREATEGROUPDATA data;
1071     DWORD dwCreateFlags = 0;
1072
1073     TRACE( "Calling SP CreateGroup\n" );
1074
1075     if( *lpidGroup == DPID_NOPARENT_GROUP )
1076       dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1077
1078     if( lpMsgHdr == NULL )
1079       dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1080
1081     if( dwFlags & DPGROUP_HIDDEN )
1082       dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1083
1084     data.idGroup           = *lpidGroup;
1085     data.dwFlags           = dwCreateFlags;
1086     data.lpSPMessageHeader = lpMsgHdr;
1087     data.lpISP             = This->dp2->spData.lpISP;
1088
1089     (*This->dp2->spData.lpCB->CreateGroup)( &data );
1090   }
1091
1092   /* Inform all other peers of the creation of a new group. If there are
1093    * no peers keep this event quiet.
1094    * Also if this message was sent to us, don't rebroadcast.
1095    */
1096   if( ( lpMsgHdr == NULL ) &&
1097       This->dp2->lpSessionDesc &&
1098       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1099   {
1100     DPMSG_CREATEPLAYERORGROUP msg;
1101     msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1102
1103     msg.dwPlayerType     = DPPLAYERTYPE_GROUP;
1104     msg.dpId             = *lpidGroup;
1105     msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1106     msg.lpData           = lpData;
1107     msg.dwDataSize       = dwDataSize;
1108     msg.dpnName          = *lpGroupName;
1109     msg.dpIdParent       = DPID_NOPARENT_GROUP;
1110     msg.dwFlags          = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1111
1112     /* FIXME: Correct to just use send effectively? */
1113     /* FIXME: Should size include data w/ message or just message "header" */
1114     /* FIXME: Check return code */
1115     DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
1116                0, 0, NULL, NULL, bAnsi );
1117   }
1118
1119   return DP_OK;
1120 }
1121
1122 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
1123           ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1124             LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1125 {
1126   *lpidGroup = DPID_UNKNOWN;
1127
1128   return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1129                             lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
1130 }
1131
1132 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1133           ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1134             LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1135 {
1136   *lpidGroup = DPID_UNKNOWN;
1137
1138   return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1139                             lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
1140 }
1141
1142
1143 static void
1144 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1145                  LPVOID lpData, DWORD dwDataSize )
1146 {
1147   /* Clear out the data with this player */
1148   if( dwFlags & DPSET_LOCAL )
1149   {
1150     if ( lpGData->dwLocalDataSize != 0 )
1151     {
1152       HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1153       lpGData->lpLocalData = NULL;
1154       lpGData->dwLocalDataSize = 0;
1155     }
1156   }
1157   else
1158   {
1159     if( lpGData->dwRemoteDataSize != 0 )
1160     {
1161       HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1162       lpGData->lpRemoteData = NULL;
1163       lpGData->dwRemoteDataSize = 0;
1164     }
1165   }
1166
1167   /* Reallocate for new data */
1168   if( lpData != NULL )
1169   {
1170     LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1171                                   sizeof( dwDataSize ) );
1172     CopyMemory( lpNewData, lpData, dwDataSize );
1173
1174     if( dwFlags & DPSET_LOCAL )
1175     {
1176       lpGData->lpLocalData     = lpData;
1177       lpGData->dwLocalDataSize = dwDataSize;
1178     }
1179     else
1180     {
1181       lpGData->lpRemoteData     = lpNewData;
1182       lpGData->dwRemoteDataSize = dwDataSize;
1183     }
1184   }
1185
1186 }
1187
1188 /* This function will just create the storage for the new player.  */
1189 static
1190 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1191                               LPDPNAME lpName, DWORD dwFlags,
1192                               HANDLE hEvent, BOOL bAnsi )
1193 {
1194   lpPlayerData lpPData;
1195
1196   TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1197
1198   /* Allocate the storage for the player and associate it with list element */
1199   lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1200   if( lpPData == NULL )
1201   {
1202     return NULL;
1203   }
1204
1205   /* Set the desired player ID */
1206   lpPData->dpid = *lpid;
1207
1208   DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1209
1210   lpPData->dwFlags = dwFlags;
1211
1212   /* If we were given an event handle, duplicate it */
1213   if( hEvent != 0 )
1214   {
1215     if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1216                           GetCurrentProcess(), &lpPData->hEvent,
1217                           0, FALSE, DUPLICATE_SAME_ACCESS )
1218       )
1219     {
1220       /* FIXME: Memory leak */
1221       ERR( "Can't duplicate player msg handle %p\n", hEvent );
1222     }
1223   }
1224
1225   /* Initialize the SP data section */
1226   lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1227
1228   TRACE( "Created player id 0x%08x\n", *lpid );
1229
1230   return lpPData;
1231 }
1232
1233 /* Delete the contents of the DPNAME struct */
1234 static void
1235 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1236 {
1237   HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1238   HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1239 }
1240
1241 /* This method assumes that all links to it are already deleted */
1242 static void
1243 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1244 {
1245   lpPlayerList lpPList;
1246
1247   TRACE( "(%p)->(0x%08x)\n", This, dpid );
1248
1249   DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1250
1251   if( lpPList == NULL )
1252   {
1253     ERR( "DPID 0x%08x not found\n", dpid );
1254     return;
1255   }
1256
1257   /* Verify that this is the last reference to the data */
1258   if( --(lpPList->lpPData->uRef) )
1259   {
1260     FIXME( "Why is this not the last reference to player?\n" );
1261     DebugBreak();
1262   }
1263
1264   /* Delete player */
1265   DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1266
1267   CloseHandle( lpPList->lpPData->hEvent );
1268   HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1269
1270   /* Delete Player List object */
1271   HeapFree( GetProcessHeap(), 0, lpPList );
1272 }
1273
1274 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1275 {
1276   lpPlayerList lpPlayers;
1277
1278   TRACE( "(%p)->(0x%08x)\n", This, dpid );
1279
1280   DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1281
1282   return lpPlayers;
1283 }
1284
1285 /* Basic area for Dst must already be allocated */
1286 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi )
1287 {
1288   if( lpSrc == NULL )
1289   {
1290     ZeroMemory( lpDst, sizeof( *lpDst ) );
1291     lpDst->dwSize = sizeof( *lpDst );
1292     return TRUE;
1293   }
1294
1295   if( lpSrc->dwSize != sizeof( *lpSrc) )
1296   {
1297     return FALSE;
1298   }
1299
1300   /* Delete any existing pointers */
1301   HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1302   HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1303
1304   /* Copy as required */
1305   CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1306
1307   if( bAnsi )
1308   {
1309     if( lpSrc->u1.lpszShortNameA )
1310     {
1311         lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1312                                              strlen(lpSrc->u1.lpszShortNameA)+1 );
1313         strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1314     }
1315     if( lpSrc->u2.lpszLongNameA )
1316     {
1317         lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1318                                               strlen(lpSrc->u2.lpszLongNameA)+1 );
1319         strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1320     }
1321   }
1322   else
1323   {
1324     if( lpSrc->u1.lpszShortNameA )
1325     {
1326         lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1327                                               (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1328         strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1329     }
1330     if( lpSrc->u2.lpszLongNameA )
1331     {
1332         lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1333                                              (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1334         strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1335     }
1336   }
1337
1338   return TRUE;
1339 }
1340
1341 static void
1342 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1343                   LPVOID lpData, DWORD dwDataSize )
1344 {
1345   /* Clear out the data with this player */
1346   if( dwFlags & DPSET_LOCAL )
1347   {
1348     if ( lpPData->dwLocalDataSize != 0 )
1349     {
1350       HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1351       lpPData->lpLocalData = NULL;
1352       lpPData->dwLocalDataSize = 0;
1353     }
1354   }
1355   else
1356   {
1357     if( lpPData->dwRemoteDataSize != 0 )
1358     {
1359       HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1360       lpPData->lpRemoteData = NULL;
1361       lpPData->dwRemoteDataSize = 0;
1362     }
1363   }
1364
1365   /* Reallocate for new data */
1366   if( lpData != NULL )
1367   {
1368     LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1369                                   sizeof( dwDataSize ) );
1370     CopyMemory( lpNewData, lpData, dwDataSize );
1371
1372     if( dwFlags & DPSET_LOCAL )
1373     {
1374       lpPData->lpLocalData     = lpData;
1375       lpPData->dwLocalDataSize = dwDataSize;
1376     }
1377     else
1378     {
1379       lpPData->lpRemoteData     = lpNewData;
1380       lpPData->dwRemoteDataSize = dwDataSize;
1381     }
1382   }
1383
1384 }
1385
1386 static HRESULT WINAPI DP_IF_CreatePlayer
1387 ( IDirectPlay2Impl* This,
1388   LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1389   LPDPID lpidPlayer,
1390   LPDPNAME lpPlayerName,
1391   HANDLE hEvent,
1392   LPVOID lpData,
1393   DWORD dwDataSize,
1394   DWORD dwFlags,
1395   BOOL bAnsi )
1396 {
1397   HRESULT hr = DP_OK;
1398   lpPlayerData lpPData;
1399   lpPlayerList lpPList;
1400   DWORD dwCreateFlags = 0;
1401
1402   TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1403          This, lpidPlayer, lpPlayerName, hEvent, lpData,
1404          dwDataSize, dwFlags, bAnsi );
1405
1406   if( dwFlags == 0 )
1407   {
1408     dwFlags = DPPLAYER_SPECTATOR;
1409   }
1410
1411   if( lpidPlayer == NULL )
1412   {
1413     return DPERR_INVALIDPARAMS;
1414   }
1415
1416
1417   /* Determine the creation flags for the player. These will be passed
1418    * to the name server if requesting a player id and to the SP when
1419    * informing it of the player creation
1420    */
1421   {
1422     if( dwFlags & DPPLAYER_SERVERPLAYER )
1423     {
1424       if( *lpidPlayer == DPID_SERVERPLAYER )
1425       {
1426         /* Server player for the host interface */
1427         dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1428       }
1429       else if( *lpidPlayer == DPID_NAME_SERVER )
1430       {
1431         /* Name server - master of everything */
1432         dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1433       }
1434       else
1435       {
1436         /* Server player for a non host interface */
1437         dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1438       }
1439     }
1440
1441     if( lpMsgHdr == NULL )
1442       dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1443   }
1444
1445   /* Verify we know how to handle all the flags */
1446   if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1447          ( dwFlags & DPPLAYER_SPECTATOR )
1448        )
1449     )
1450   {
1451     /* Assume non fatal failure */
1452     ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1453   }
1454
1455   /* If the name is not specified, we must provide one */
1456   if( *lpidPlayer == DPID_UNKNOWN )
1457   {
1458     /* If we are the session master, we dish out the group/player ids */
1459     if( This->dp2->bHostInterface )
1460     {
1461       *lpidPlayer = DP_NextObjectId();
1462     }
1463     else
1464     {
1465       hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1466
1467       if( FAILED(hr) )
1468       {
1469         ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1470         return hr;
1471       }
1472     }
1473   }
1474   else
1475   {
1476     /* FIXME: Would be nice to perhaps verify that we don't already have
1477      *        this player.
1478      */
1479   }
1480
1481   /* FIXME: Should we be storing these dwFlags or the creation ones? */
1482   lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags,
1483                              hEvent, bAnsi );
1484
1485   if( lpPData == NULL )
1486   {
1487     return DPERR_CANTADDPLAYER;
1488   }
1489
1490   /* Create the list object and link it in */
1491   lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1492   if( lpPList == NULL )
1493   {
1494     FIXME( "Memory leak\n" );
1495     return DPERR_CANTADDPLAYER;
1496   }
1497
1498   lpPData->uRef = 1;
1499   lpPList->lpPData = lpPData;
1500
1501   /* Add the player to the system group */
1502   DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1503
1504   /* Update the information and send it to all players in the session */
1505   DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1506
1507   /* Let the SP know that we've created this player */
1508   if( This->dp2->spData.lpCB->CreatePlayer )
1509   {
1510     DPSP_CREATEPLAYERDATA data;
1511
1512     data.idPlayer          = *lpidPlayer;
1513     data.dwFlags           = dwCreateFlags;
1514     data.lpSPMessageHeader = lpMsgHdr;
1515     data.lpISP             = This->dp2->spData.lpISP;
1516
1517     TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1518            *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1519
1520     hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1521   }
1522
1523   if( FAILED(hr) )
1524   {
1525     ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1526     return hr;
1527   }
1528
1529   /* Now let the SP know that this player is a member of the system group */
1530   if( This->dp2->spData.lpCB->AddPlayerToGroup )
1531   {
1532     DPSP_ADDPLAYERTOGROUPDATA data;
1533
1534     data.idPlayer = *lpidPlayer;
1535     data.idGroup  = DPID_SYSTEM_GROUP;
1536     data.lpISP    = This->dp2->spData.lpISP;
1537
1538     TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1539
1540     hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1541   }
1542
1543   if( FAILED(hr) )
1544   {
1545     ERR( "Failed to add player to sys group with sp: %s\n",
1546          DPLAYX_HresultToString(hr) );
1547     return hr;
1548   }
1549
1550 #if 1
1551   if( This->dp2->bHostInterface == FALSE )
1552   {
1553     /* Let the name server know about the creation of this player */
1554     /* FIXME: Is this only to be done for the creation of a server player or
1555      *        is this used for regular players? If only for server players, move
1556      *        this call to DP_SecureOpen(...);
1557      */
1558 #if 0
1559     TRACE( "Sending message to self to get my addr\n" );
1560     DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1561 #endif
1562
1563     hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1564   }
1565 #else
1566   /* Inform all other peers of the creation of a new player. If there are
1567    * no peers keep this quiet.
1568    * Also, if this was a remote event, no need to rebroadcast it.
1569    */
1570   if( ( lpMsgHdr == NULL ) &&
1571       This->dp2->lpSessionDesc &&
1572       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1573   {
1574     DPMSG_CREATEPLAYERORGROUP msg;
1575     msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1576
1577     msg.dwPlayerType     = DPPLAYERTYPE_PLAYER;
1578     msg.dpId             = *lpidPlayer;
1579     msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1580     msg.lpData           = lpData;
1581     msg.dwDataSize       = dwDataSize;
1582     msg.dpnName          = *lpPlayerName;
1583     msg.dpIdParent       = DPID_NOPARENT_GROUP;
1584     msg.dwFlags          = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1585
1586     /* FIXME: Correct to just use send effectively? */
1587     /* FIXME: Should size include data w/ message or just message "header" */
1588     /* FIXME: Check return code */
1589     hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1590                     sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1591   }
1592 #endif
1593
1594   return hr;
1595 }
1596
1597 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1598           ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1599             HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1600 {
1601   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1602
1603   if( dwFlags & DPPLAYER_SERVERPLAYER )
1604   {
1605     *lpidPlayer = DPID_SERVERPLAYER;
1606   }
1607   else
1608   {
1609     *lpidPlayer = DPID_UNKNOWN;
1610   }
1611
1612   return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1613                            lpData, dwDataSize, dwFlags, TRUE );
1614 }
1615
1616 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1617           ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1618             HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1619 {
1620   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1621
1622   if( dwFlags & DPPLAYER_SERVERPLAYER )
1623   {
1624     *lpidPlayer = DPID_SERVERPLAYER;
1625   }
1626   else
1627   {
1628     *lpidPlayer = DPID_UNKNOWN;
1629   }
1630
1631   return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1632                            lpData, dwDataSize, dwFlags, FALSE );
1633 }
1634
1635 static DPID DP_GetRemoteNextObjectId(void)
1636 {
1637   FIXME( ":stub\n" );
1638
1639   /* Hack solution */
1640   return DP_NextObjectId();
1641 }
1642
1643 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
1644           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1645             DPID idPlayer, BOOL bAnsi )
1646 {
1647   HRESULT hr = DP_OK;
1648
1649   lpGroupData  lpGData;
1650   lpPlayerList lpPList;
1651
1652   TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
1653          This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1654
1655   /* Find the group */
1656   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1657   {
1658     return DPERR_INVALIDGROUP;
1659   }
1660
1661   /* Find the player */
1662   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1663   {
1664     return DPERR_INVALIDPLAYER;
1665   }
1666
1667   /* Remove the player shortcut from the group */
1668   DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1669
1670   if( lpPList == NULL )
1671   {
1672     return DPERR_INVALIDPLAYER;
1673   }
1674
1675   /* One less reference */
1676   lpPList->lpPData->uRef--;
1677
1678   /* Delete the Player List element */
1679   HeapFree( GetProcessHeap(), 0, lpPList );
1680
1681   /* Inform the SP if they care */
1682   if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1683   {
1684     DPSP_REMOVEPLAYERFROMGROUPDATA data;
1685
1686     TRACE( "Calling SP RemovePlayerFromGroup\n" );
1687
1688     data.idPlayer = idPlayer;
1689     data.idGroup  = idGroup;
1690     data.lpISP    = This->dp2->spData.lpISP;
1691
1692     hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1693   }
1694
1695   /* Need to send a DELETEPLAYERFROMGROUP message */
1696   FIXME( "Need to send a message\n" );
1697
1698   return hr;
1699 }
1700
1701 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1702           ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1703 {
1704   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1705   return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1706 }
1707
1708 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1709           ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1710 {
1711   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1712   return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1713 }
1714
1715 typedef struct _DPRGOPContext
1716 {
1717   IDirectPlay3Impl* This;
1718   BOOL              bAnsi;
1719   DPID              idGroup;
1720 } DPRGOPContext, *lpDPRGOPContext;
1721
1722 static BOOL CALLBACK
1723 cbRemoveGroupOrPlayer(
1724     DPID            dpId,
1725     DWORD           dwPlayerType,
1726     LPCDPNAME       lpName,
1727     DWORD           dwFlags,
1728     LPVOID          lpContext )
1729 {
1730   lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1731
1732   TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1733            dpId, dwPlayerType, lpCtxt->idGroup );
1734
1735   if( dwPlayerType == DPPLAYERTYPE_GROUP )
1736   {
1737     if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1738                                             dpId )
1739               )
1740       )
1741     {
1742       ERR( "Unable to delete group 0x%08x from group 0x%08x\n",
1743              dpId, lpCtxt->idGroup );
1744     }
1745   }
1746   else
1747   {
1748     if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1749                                              NULL, lpCtxt->idGroup,
1750                                              dpId, lpCtxt->bAnsi )
1751               )
1752       )
1753     {
1754       ERR( "Unable to delete player 0x%08x from grp 0x%08x\n",
1755              dpId, lpCtxt->idGroup );
1756     }
1757   }
1758
1759   return TRUE; /* Continue enumeration */
1760 }
1761
1762 static HRESULT WINAPI DP_IF_DestroyGroup
1763           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1764 {
1765   lpGroupData lpGData;
1766   DPRGOPContext context;
1767
1768   FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1769          This, lpMsgHdr, idGroup, bAnsi );
1770
1771   /* Find the group */
1772   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1773   {
1774     return DPERR_INVALIDPLAYER; /* yes player */
1775   }
1776
1777   context.This    = (IDirectPlay3Impl*)This;
1778   context.bAnsi   = bAnsi;
1779   context.idGroup = idGroup;
1780
1781   /* Remove all players that this group has */
1782   DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1783                           cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1784
1785   /* Remove all links to groups that this group has since this is dp3 */
1786   DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1787                            cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1788
1789   /* Remove this group from the parent group - if it has one */
1790   if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1791       ( lpGData->parent != DPID_SYSTEM_GROUP )
1792     )
1793   {
1794     DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1795                                 idGroup );
1796   }
1797
1798   /* Now delete this group data and list from the system group */
1799   DP_DeleteGroup( This, idGroup );
1800
1801   /* Let the SP know that we've destroyed this group */
1802   if( This->dp2->spData.lpCB->DeleteGroup )
1803   {
1804     DPSP_DELETEGROUPDATA data;
1805
1806     FIXME( "data.dwFlags is incorrect\n" );
1807
1808     data.idGroup = idGroup;
1809     data.dwFlags = 0;
1810     data.lpISP   = This->dp2->spData.lpISP;
1811
1812     (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1813   }
1814
1815   FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1816
1817   return DP_OK;
1818 }
1819
1820 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1821           ( LPDIRECTPLAY2A iface, DPID idGroup )
1822 {
1823   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1824   return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1825 }
1826
1827 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1828           ( LPDIRECTPLAY2 iface, DPID idGroup )
1829 {
1830   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1831   return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1832 }
1833
1834 typedef struct _DPFAGContext
1835 {
1836   IDirectPlay2Impl* This;
1837   DPID              idPlayer;
1838   BOOL              bAnsi;
1839 } DPFAGContext, *lpDPFAGContext;
1840
1841 static HRESULT WINAPI DP_IF_DestroyPlayer
1842           ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1843 {
1844   DPFAGContext cbContext;
1845
1846   FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1847          This, lpMsgHdr, idPlayer, bAnsi );
1848
1849   if( This->dp2->connectionInitialized == NO_PROVIDER )
1850   {
1851     return DPERR_UNINITIALIZED;
1852   }
1853
1854   if( DP_FindPlayer( This, idPlayer ) == NULL )
1855   {
1856     return DPERR_INVALIDPLAYER;
1857   }
1858
1859   /* FIXME: If the player is remote, we must be the host to delete this */
1860
1861   cbContext.This     = This;
1862   cbContext.idPlayer = idPlayer;
1863   cbContext.bAnsi    = bAnsi;
1864
1865   /* Find each group and call DeletePlayerFromGroup if the player is a
1866      member of the group */
1867   DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
1868                     (LPVOID)&cbContext, DPENUMGROUPS_ALL, bAnsi );
1869
1870   /* Now delete player and player list from the sys group */
1871   DP_DeletePlayer( This, idPlayer );
1872
1873   /* Let the SP know that we've destroyed this group */
1874   if( This->dp2->spData.lpCB->DeletePlayer )
1875   {
1876     DPSP_DELETEPLAYERDATA data;
1877
1878     FIXME( "data.dwFlags is incorrect\n" );
1879
1880     data.idPlayer = idPlayer;
1881     data.dwFlags = 0;
1882     data.lpISP   = This->dp2->spData.lpISP;
1883
1884     (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1885   }
1886
1887   FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1888
1889   return DP_OK;
1890 }
1891
1892 static BOOL CALLBACK
1893 cbDeletePlayerFromAllGroups(
1894     DPID            dpId,
1895     DWORD           dwPlayerType,
1896     LPCDPNAME       lpName,
1897     DWORD           dwFlags,
1898     LPVOID          lpContext )
1899 {
1900   lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1901
1902   if( dwPlayerType == DPPLAYERTYPE_GROUP )
1903   {
1904     DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
1905                                  lpCtxt->bAnsi );
1906
1907     /* Enumerate all groups in this group since this will normally only
1908      * be called for top level groups
1909      */
1910     DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
1911                              dpId, NULL,
1912                              cbDeletePlayerFromAllGroups,
1913                              (LPVOID)lpContext, DPENUMGROUPS_ALL,
1914                              lpCtxt->bAnsi );
1915
1916   }
1917   else
1918   {
1919     ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
1920   }
1921
1922   return TRUE;
1923 }
1924
1925 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
1926           ( LPDIRECTPLAY2A iface, DPID idPlayer )
1927 {
1928   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1929   return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1930 }
1931
1932 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1933           ( LPDIRECTPLAY2 iface, DPID idPlayer )
1934 {
1935   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1936   return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1937 }
1938
1939 static HRESULT WINAPI DP_IF_EnumGroupPlayers
1940           ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1941             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1942             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1943 {
1944   lpGroupData  lpGData;
1945   lpPlayerList lpPList;
1946
1947   FIXME("(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
1948           This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1949           lpContext, dwFlags, bAnsi );
1950
1951   if( This->dp2->connectionInitialized == NO_PROVIDER )
1952   {
1953     return DPERR_UNINITIALIZED;
1954   }
1955
1956   /* Find the group */
1957   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1958   {
1959     return DPERR_INVALIDGROUP;
1960   }
1961
1962   if( DPQ_IS_EMPTY( lpGData->players ) )
1963   {
1964     return DP_OK;
1965   }
1966
1967   lpPList = DPQ_FIRST( lpGData->players );
1968
1969   /* Walk the players in this group */
1970   for( ;; )
1971   {
1972     /* We do not enum the name server or app server as they are of no
1973      * concequence to the end user.
1974      */
1975     if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
1976         ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
1977       )
1978     {
1979
1980       /* FIXME: Need to add stuff for dwFlags checking */
1981
1982       if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1983                                    &lpPList->lpPData->name,
1984                                    lpPList->lpPData->dwFlags,
1985                                    lpContext )
1986         )
1987       {
1988         /* User requested break */
1989         return DP_OK;
1990       }
1991     }
1992
1993     if( DPQ_IS_ENDOFLIST( lpPList->players ) )
1994     {
1995       break;
1996     }
1997
1998     lpPList = DPQ_NEXT( lpPList->players );
1999   }
2000
2001   return DP_OK;
2002 }
2003
2004 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
2005           ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
2006             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2007             LPVOID lpContext, DWORD dwFlags )
2008 {
2009   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2010   return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2011                                lpEnumPlayersCallback2, lpContext,
2012                                dwFlags, TRUE );
2013 }
2014
2015 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
2016           ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
2017             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2018             LPVOID lpContext, DWORD dwFlags )
2019 {
2020   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2021   return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2022                                lpEnumPlayersCallback2, lpContext,
2023                                dwFlags, FALSE );
2024 }
2025
2026 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2027 static HRESULT WINAPI DP_IF_EnumGroups
2028           ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2029             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2030             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2031 {
2032   return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2033                                   DPID_SYSTEM_GROUP, lpguidInstance,
2034                                   lpEnumPlayersCallback2, lpContext,
2035                                   dwFlags, bAnsi );
2036 }
2037
2038 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2039           ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2040             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2041             LPVOID lpContext, DWORD dwFlags )
2042 {
2043   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2044   return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2045                          lpContext, dwFlags, TRUE );
2046 }
2047
2048 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2049           ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2050             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2051             LPVOID lpContext, DWORD dwFlags )
2052 {
2053   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2054   return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2055                          lpContext, dwFlags, FALSE );
2056 }
2057
2058 static HRESULT WINAPI DP_IF_EnumPlayers
2059           ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2060             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2061             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2062 {
2063   return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
2064                                  lpEnumPlayersCallback2, lpContext,
2065                                  dwFlags, bAnsi );
2066 }
2067
2068 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2069           ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2070             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2071             LPVOID lpContext, DWORD dwFlags )
2072 {
2073   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2074   return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2075                           lpContext, dwFlags, TRUE );
2076 }
2077
2078 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2079           ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2080             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2081             LPVOID lpContext, DWORD dwFlags )
2082 {
2083   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2084   return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2085                           lpContext, dwFlags, FALSE );
2086 }
2087
2088 /* This function should call the registered callback function that the user
2089    passed into EnumSessions for each entry available.
2090  */
2091 static void DP_InvokeEnumSessionCallbacks
2092        ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2093          LPVOID lpNSInfo,
2094          DWORD dwTimeout,
2095          LPVOID lpContext )
2096 {
2097   LPDPSESSIONDESC2 lpSessionDesc;
2098
2099   FIXME( ": not checking for conditions\n" );
2100
2101   /* Not sure if this should be pruning but it's convenient */
2102   NS_PruneSessionCache( lpNSInfo );
2103
2104   NS_ResetSessionEnumeration( lpNSInfo );
2105
2106   /* Enumerate all sessions */
2107   /* FIXME: Need to indicate ANSI */
2108   while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2109   {
2110     TRACE( "EnumSessionsCallback2 invoked\n" );
2111     if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2112     {
2113       return;
2114     }
2115   }
2116
2117   /* Invoke one last time to indicate that there is no more to come */
2118   lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2119 }
2120
2121 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2122 {
2123   EnumSessionAsyncCallbackData* data = (EnumSessionAsyncCallbackData*)lpContext;
2124   HANDLE hSuicideRequest = data->hSuicideRequest;
2125   DWORD dwTimeout = data->dwTimeout;
2126
2127   TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
2128
2129   for( ;; )
2130   {
2131     HRESULT hr;
2132
2133     /* Sleep up to dwTimeout waiting for request to terminate thread */
2134     if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2135     {
2136       TRACE( "Thread terminating on terminate request\n" );
2137       break;
2138     }
2139
2140     /* Now resend the enum request */
2141     hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2142                                          data->dwEnumSessionFlags,
2143                                          data->lpSpData );
2144
2145     if( FAILED(hr) )
2146     {
2147       ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2148       /* FIXME: Should we kill this thread? How to inform the main thread? */
2149     }
2150
2151   }
2152
2153   TRACE( "Thread terminating\n" );
2154
2155   /* Clean up the thread data */
2156   CloseHandle( hSuicideRequest );
2157   HeapFree( GetProcessHeap(), 0, lpContext );
2158
2159   /* FIXME: Need to have some notification to main app thread that this is
2160    *        dead. It would serve two purposes. 1) allow sync on termination
2161    *        so that we don't actually send something to ourselves when we
2162    *        become name server (race condition) and 2) so that if we die
2163    *        abnormally something else will be able to tell.
2164    */
2165
2166   return 1;
2167 }
2168
2169 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
2170 {
2171   /* Does a thread exist? If so we were doing an async enum session */
2172   if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2173   {
2174     TRACE( "Killing EnumSession thread %p\n",
2175            This->dp2->hEnumSessionThread );
2176
2177     /* Request that the thread kill itself nicely */
2178     SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2179     CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2180
2181     /* We no longer need to know about the thread */
2182     CloseHandle( This->dp2->hEnumSessionThread );
2183
2184     This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2185   }
2186 }
2187
2188 static HRESULT WINAPI DP_IF_EnumSessions
2189           ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2190             LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2191             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2192 {
2193   HRESULT hr = DP_OK;
2194
2195   TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x,%u)\n",
2196          This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2197          bAnsi );
2198
2199   /* Can't enumerate if the interface is already open */
2200   if( This->dp2->bConnectionOpen )
2201   {
2202     return DPERR_GENERIC;
2203   }
2204
2205 #if 1
2206   /* The loading of a lobby provider _seems_ to require a backdoor loading
2207    * of the service provider to also associate with this DP object. This is
2208    * because the app doesn't seem to have to call EnumConnections and
2209    * InitializeConnection for the SP before calling this method. As such
2210    * we'll do their dirty work for them with a quick hack so as to always
2211    * load the TCP/IP service provider.
2212    *
2213    * The correct solution would seem to involve creating a dialog box which
2214    * contains the possible SPs. These dialog boxes most likely follow SDK
2215    * examples.
2216    */
2217    if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2218    {
2219      LPVOID lpConnection;
2220      DWORD  dwSize;
2221
2222      WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2223
2224      if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2225      {
2226        ERR( "Can't build compound addr\n" );
2227        return DPERR_GENERIC;
2228      }
2229
2230      hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2231                                       0, bAnsi );
2232      if( FAILED(hr) )
2233      {
2234        return hr;
2235      }
2236
2237      /* Free up the address buffer */
2238      HeapFree( GetProcessHeap(), 0, lpConnection );
2239
2240      /* The SP is now initialized */
2241      This->dp2->bSPInitialized = TRUE;
2242    }
2243 #endif
2244
2245
2246   /* Use the service provider default? */
2247   if( dwTimeout == 0 )
2248   {
2249     DPCAPS spCaps;
2250     spCaps.dwSize = sizeof( spCaps );
2251
2252     DP_IF_GetCaps( This, &spCaps, 0 );
2253     dwTimeout = spCaps.dwTimeout;
2254
2255     /* The service provider doesn't provide one either! */
2256     if( dwTimeout == 0 )
2257     {
2258       /* Provide the TCP/IP default */
2259       dwTimeout = DPMSG_WAIT_5_SECS;
2260     }
2261   }
2262
2263   if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2264   {
2265     DP_KillEnumSessionThread( This );
2266     return hr;
2267   }
2268
2269   /* FIXME: Interface locking sucks in this method */
2270   if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2271   {
2272     /* Enumerate everything presently in the local session cache */
2273     DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2274                                    This->dp2->lpNameServerData, dwTimeout,
2275                                    lpContext );
2276
2277
2278     /* See if we've already created a thread to service this interface */
2279     if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2280     {
2281       DWORD dwThreadId;
2282
2283       /* Send the first enum request inline since the user may cancel a dialog
2284        * if one is presented. Also, may also have a connecting return code.
2285        */
2286       hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2287                                            dwFlags, &This->dp2->spData );
2288
2289       if( !FAILED(hr) )
2290       {
2291         EnumSessionAsyncCallbackData* lpData
2292           = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2293         /* FIXME: need to kill the thread on object deletion */
2294         lpData->lpSpData  = &This->dp2->spData;
2295
2296         CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
2297         lpData->dwEnumSessionFlags = dwFlags;
2298         lpData->dwTimeout = dwTimeout;
2299
2300         This->dp2->hKillEnumSessionThreadEvent =
2301           CreateEventW( NULL, TRUE, FALSE, NULL );
2302
2303         if( !DuplicateHandle( GetCurrentProcess(),
2304                               This->dp2->hKillEnumSessionThreadEvent,
2305                               GetCurrentProcess(),
2306                               &lpData->hSuicideRequest,
2307                               0, FALSE, DUPLICATE_SAME_ACCESS )
2308           )
2309         {
2310           ERR( "Can't duplicate thread killing handle\n" );
2311         }
2312
2313         TRACE( ": creating EnumSessionsRequest thread\n" );
2314
2315         This->dp2->hEnumSessionThread = CreateThread( NULL,
2316                                                       0,
2317                                                       DP_EnumSessionsSendAsyncRequestThread,
2318                                                       lpData,
2319                                                       0,
2320                                                       &dwThreadId );
2321       }
2322     }
2323   }
2324   else
2325   {
2326     /* Invalidate the session cache for the interface */
2327     NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2328
2329     /* Send the broadcast for session enumeration */
2330     hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2331                                          dwFlags,
2332                                          &This->dp2->spData );
2333
2334
2335     SleepEx( dwTimeout, FALSE );
2336
2337     DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2338                                    This->dp2->lpNameServerData, dwTimeout,
2339                                    lpContext );
2340   }
2341
2342   return hr;
2343 }
2344
2345 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2346           ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2347             LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2348             LPVOID lpContext, DWORD dwFlags )
2349 {
2350   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2351   return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2352                              lpContext, dwFlags, TRUE );
2353 }
2354
2355 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2356           ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2357             LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2358             LPVOID lpContext, DWORD dwFlags )
2359 {
2360   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2361   return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2362                              lpContext, dwFlags, FALSE );
2363 }
2364
2365 static HRESULT WINAPI DP_IF_GetPlayerCaps
2366           ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2367             DWORD dwFlags )
2368 {
2369   DPSP_GETCAPSDATA data;
2370
2371   TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
2372
2373   /* Query the service provider */
2374   data.idPlayer = idPlayer;
2375   data.dwFlags  = dwFlags;
2376   data.lpCaps   = lpDPCaps;
2377   data.lpISP    = This->dp2->spData.lpISP;
2378
2379   return (*This->dp2->spData.lpCB->GetCaps)( &data );
2380 }
2381
2382 static HRESULT WINAPI DP_IF_GetCaps
2383           ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2384 {
2385   return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2386 }
2387
2388 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2389           ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2390 {
2391   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2392   return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2393 }
2394
2395 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2396           ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2397 {
2398   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2399   return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2400 }
2401
2402 static HRESULT WINAPI DP_IF_GetGroupData
2403           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2404             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2405 {
2406   lpGroupData lpGData;
2407   DWORD dwRequiredBufferSize;
2408   LPVOID lpCopyDataFrom;
2409
2410   TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2411          This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2412
2413   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2414   {
2415     return DPERR_INVALIDGROUP;
2416   }
2417
2418   /* How much buffer is required? */
2419   if( dwFlags & DPSET_LOCAL )
2420   {
2421     dwRequiredBufferSize = lpGData->dwLocalDataSize;
2422     lpCopyDataFrom       = lpGData->lpLocalData;
2423   }
2424   else
2425   {
2426     dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2427     lpCopyDataFrom       = lpGData->lpRemoteData;
2428   }
2429
2430   /* Is the user requesting to know how big a buffer is required? */
2431   if( ( lpData == NULL ) ||
2432       ( *lpdwDataSize < dwRequiredBufferSize )
2433     )
2434   {
2435     *lpdwDataSize = dwRequiredBufferSize;
2436     return DPERR_BUFFERTOOSMALL;
2437   }
2438
2439   CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2440
2441   return DP_OK;
2442 }
2443
2444 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2445           ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2446             LPDWORD lpdwDataSize, DWORD dwFlags )
2447 {
2448   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2449   return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2450                            dwFlags, TRUE );
2451 }
2452
2453 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2454           ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2455             LPDWORD lpdwDataSize, DWORD dwFlags )
2456 {
2457   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2458   return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2459                            dwFlags, FALSE );
2460 }
2461
2462 static HRESULT WINAPI DP_IF_GetGroupName
2463           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2464             LPDWORD lpdwDataSize, BOOL bAnsi )
2465 {
2466   lpGroupData lpGData;
2467   LPDPNAME    lpName = (LPDPNAME)lpData;
2468   DWORD       dwRequiredDataSize;
2469
2470   FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2471           This, idGroup, lpData, lpdwDataSize, bAnsi );
2472
2473   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2474   {
2475     return DPERR_INVALIDGROUP;
2476   }
2477
2478   dwRequiredDataSize = lpGData->name.dwSize;
2479
2480   if( lpGData->name.u1.lpszShortNameA )
2481   {
2482     dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2483   }
2484
2485   if( lpGData->name.u2.lpszLongNameA )
2486   {
2487     dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2488   }
2489
2490   if( ( lpData == NULL ) ||
2491       ( *lpdwDataSize < dwRequiredDataSize )
2492     )
2493   {
2494     *lpdwDataSize = dwRequiredDataSize;
2495     return DPERR_BUFFERTOOSMALL;
2496   }
2497
2498   /* Copy the structure */
2499   CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2500
2501   if( lpGData->name.u1.lpszShortNameA )
2502   {
2503     strcpy( ((char*)lpName)+lpGData->name.dwSize,
2504             lpGData->name.u1.lpszShortNameA );
2505   }
2506   else
2507   {
2508     lpName->u1.lpszShortNameA = NULL;
2509   }
2510
2511   if( lpGData->name.u1.lpszShortNameA )
2512   {
2513     strcpy( ((char*)lpName)+lpGData->name.dwSize,
2514             lpGData->name.u2.lpszLongNameA );
2515   }
2516   else
2517   {
2518     lpName->u2.lpszLongNameA = NULL;
2519   }
2520
2521   return DP_OK;
2522 }
2523
2524 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2525           ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2526             LPDWORD lpdwDataSize )
2527 {
2528   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2529   return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2530 }
2531
2532 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2533           ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2534             LPDWORD lpdwDataSize )
2535 {
2536   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2537   return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2538 }
2539
2540 static HRESULT WINAPI DP_IF_GetMessageCount
2541           ( IDirectPlay2Impl* This, DPID idPlayer,
2542             LPDWORD lpdwCount, BOOL bAnsi )
2543 {
2544   FIXME("(%p)->(0x%08x,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2545   return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2546                                 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2547                                 bAnsi );
2548 }
2549
2550 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2551           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2552 {
2553   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2554   return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2555 }
2556
2557 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2558           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2559 {
2560   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2561   return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2562 }
2563
2564 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2565           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2566 {
2567   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2568   FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2569   return DP_OK;
2570 }
2571
2572 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2573           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2574 {
2575   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2576   FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2577   return DP_OK;
2578 }
2579
2580 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2581           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2582             DWORD dwFlags )
2583 {
2584   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2585   return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2586 }
2587
2588 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2589           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2590             DWORD dwFlags )
2591 {
2592   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2593   return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2594 }
2595
2596 static HRESULT WINAPI DP_IF_GetPlayerData
2597           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2598             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2599 {
2600   lpPlayerList lpPList;
2601   DWORD dwRequiredBufferSize;
2602   LPVOID lpCopyDataFrom;
2603
2604   TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2605          This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2606
2607   if( This->dp2->connectionInitialized == NO_PROVIDER )
2608   {
2609     return DPERR_UNINITIALIZED;
2610   }
2611
2612   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2613   {
2614     return DPERR_INVALIDPLAYER;
2615   }
2616
2617   /* How much buffer is required? */
2618   if( dwFlags & DPSET_LOCAL )
2619   {
2620     dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2621     lpCopyDataFrom       = lpPList->lpPData->lpLocalData;
2622   }
2623   else
2624   {
2625     dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2626     lpCopyDataFrom       = lpPList->lpPData->lpRemoteData;
2627   }
2628
2629   /* Is the user requesting to know how big a buffer is required? */
2630   if( ( lpData == NULL ) ||
2631       ( *lpdwDataSize < dwRequiredBufferSize )
2632     )
2633   {
2634     *lpdwDataSize = dwRequiredBufferSize;
2635     return DPERR_BUFFERTOOSMALL;
2636   }
2637
2638   CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2639
2640   return DP_OK;
2641 }
2642
2643 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2644           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2645             LPDWORD lpdwDataSize, DWORD dwFlags )
2646 {
2647   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2648   return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2649                             dwFlags, TRUE );
2650 }
2651
2652 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2653           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2654             LPDWORD lpdwDataSize, DWORD dwFlags )
2655 {
2656   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2657   return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2658                             dwFlags, FALSE );
2659 }
2660
2661 static HRESULT WINAPI DP_IF_GetPlayerName
2662           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2663             LPDWORD lpdwDataSize, BOOL bAnsi )
2664 {
2665   lpPlayerList lpPList;
2666   LPDPNAME    lpName = (LPDPNAME)lpData;
2667   DWORD       dwRequiredDataSize;
2668
2669   FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2670          This, idPlayer, lpData, lpdwDataSize, bAnsi );
2671
2672   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2673   {
2674     return DPERR_INVALIDPLAYER;
2675   }
2676
2677   dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2678
2679   if( lpPList->lpPData->name.u1.lpszShortNameA )
2680   {
2681     dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2682   }
2683
2684   if( lpPList->lpPData->name.u2.lpszLongNameA )
2685   {
2686     dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2687   }
2688
2689   if( ( lpData == NULL ) ||
2690       ( *lpdwDataSize < dwRequiredDataSize )
2691     )
2692   {
2693     *lpdwDataSize = dwRequiredDataSize;
2694     return DPERR_BUFFERTOOSMALL;
2695   }
2696
2697   /* Copy the structure */
2698   CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2699
2700   if( lpPList->lpPData->name.u1.lpszShortNameA )
2701   {
2702     strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2703             lpPList->lpPData->name.u1.lpszShortNameA );
2704   }
2705   else
2706   {
2707     lpName->u1.lpszShortNameA = NULL;
2708   }
2709
2710   if( lpPList->lpPData->name.u1.lpszShortNameA )
2711   {
2712     strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2713             lpPList->lpPData->name.u2.lpszLongNameA );
2714   }
2715   else
2716   {
2717     lpName->u2.lpszLongNameA = NULL;
2718   }
2719
2720   return DP_OK;
2721 }
2722
2723 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2724           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2725             LPDWORD lpdwDataSize )
2726 {
2727   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2728   return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2729 }
2730
2731 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2732           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2733             LPDWORD lpdwDataSize )
2734 {
2735   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2736   return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2737 }
2738
2739 static HRESULT WINAPI DP_GetSessionDesc
2740           ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2741             BOOL bAnsi )
2742 {
2743   DWORD dwRequiredSize;
2744
2745   TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2746
2747   if( This->dp2->connectionInitialized == NO_PROVIDER )
2748   {
2749     return DPERR_UNINITIALIZED;
2750   }
2751
2752   if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2753   {
2754     return DPERR_INVALIDPARAMS;
2755   }
2756
2757   /* FIXME: Get from This->dp2->lpSessionDesc */
2758   dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2759
2760   if ( ( lpData == NULL ) ||
2761        ( *lpdwDataSize < dwRequiredSize )
2762      )
2763   {
2764     *lpdwDataSize = dwRequiredSize;
2765     return DPERR_BUFFERTOOSMALL;
2766   }
2767
2768   DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2769
2770   return DP_OK;
2771 }
2772
2773 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2774           ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2775 {
2776   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2777   return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2778 }
2779
2780 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2781           ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2782 {
2783   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2784   return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2785 }
2786
2787 /* Intended only for COM compatibility. Always returns an error. */
2788 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2789           ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2790 {
2791   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2792   TRACE("(%p)->(%p): stub\n", This, lpGUID );
2793   return DPERR_ALREADYINITIALIZED;
2794 }
2795
2796 /* Intended only for COM compatibility. Always returns an error. */
2797 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2798           ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2799 {
2800   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2801   TRACE("(%p)->(%p): stub\n", This, lpGUID );
2802   return DPERR_ALREADYINITIALIZED;
2803 }
2804
2805
2806 static HRESULT WINAPI DP_SecureOpen
2807           ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2808             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2809             BOOL bAnsi )
2810 {
2811   HRESULT hr = DP_OK;
2812
2813   FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2814          This, lpsd, dwFlags, lpSecurity, lpCredentials );
2815
2816   if( This->dp2->bConnectionOpen )
2817   {
2818     TRACE( ": rejecting already open connection.\n" );
2819     return DPERR_ALREADYINITIALIZED;
2820   }
2821
2822   /* If we're enumerating, kill the thread */
2823   DP_KillEnumSessionThread( This );
2824
2825   if( dwFlags & DPOPEN_CREATE )
2826   {
2827     /* Rightoo - this computer is the host and the local computer needs to be
2828        the name server so that others can join this session */
2829     NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2830
2831     This->dp2->bHostInterface = TRUE;
2832
2833     hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2834     if( FAILED( hr ) )
2835     {
2836       ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2837       return hr;
2838     }
2839   }
2840
2841   /* Invoke the conditional callback for the service provider */
2842   if( This->dp2->spData.lpCB->Open )
2843   {
2844     DPSP_OPENDATA data;
2845
2846     FIXME( "Not all data fields are correct. Need new parameter\n" );
2847
2848     data.bCreate           = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
2849     data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2850                                                         : NS_GetNSAddr( This->dp2->lpNameServerData );
2851     data.lpISP             = This->dp2->spData.lpISP;
2852     data.bReturnStatus     = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
2853     data.dwOpenFlags       = dwFlags;
2854     data.dwSessionFlags    = This->dp2->lpSessionDesc->dwFlags;
2855
2856     hr = (*This->dp2->spData.lpCB->Open)(&data);
2857     if( FAILED( hr ) )
2858     {
2859       ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2860       return hr;
2861     }
2862   }
2863
2864   {
2865     /* Create the system group of which everything is a part of */
2866     DPID systemGroup = DPID_SYSTEM_GROUP;
2867
2868     hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2869                             NULL, 0, 0, TRUE );
2870
2871   }
2872
2873   if( dwFlags & DPOPEN_JOIN )
2874   {
2875     DPID dpidServerId = DPID_UNKNOWN;
2876
2877     /* Create the server player for this interface. This way we can receive
2878      * messages for this session.
2879      */
2880     /* FIXME: I suppose that we should be setting an event for a receive
2881      *        type of thing. That way the messaging thread could know to wake
2882      *        up. DPlay would then trigger the hEvent for the player the
2883      *        message is directed to.
2884      */
2885     hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2886                              0,
2887                              DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2888
2889   }
2890   else if( dwFlags & DPOPEN_CREATE )
2891   {
2892     DPID dpidNameServerId = DPID_NAME_SERVER;
2893
2894     hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2895                              0, DPPLAYER_SERVERPLAYER, bAnsi );
2896   }
2897
2898   if( FAILED(hr) )
2899   {
2900     ERR( "Couldn't create name server/system player: %s\n",
2901          DPLAYX_HresultToString(hr) );
2902   }
2903
2904   return hr;
2905 }
2906
2907 static HRESULT WINAPI DirectPlay2AImpl_Open
2908           ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2909 {
2910   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2911   TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2912   return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
2913 }
2914
2915 static HRESULT WINAPI DirectPlay2WImpl_Open
2916           ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2917 {
2918   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2919   TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2920   return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
2921 }
2922
2923 static HRESULT WINAPI DP_IF_Receive
2924           ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2925             DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2926 {
2927   LPDPMSG lpMsg = NULL;
2928
2929   FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
2930          This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2931
2932   if( This->dp2->connectionInitialized == NO_PROVIDER )
2933   {
2934     return DPERR_UNINITIALIZED;
2935   }
2936
2937   if( dwFlags == 0 )
2938   {
2939     dwFlags = DPRECEIVE_ALL;
2940   }
2941
2942   /* If the lpData is NULL, we must be peeking the message */
2943   if(  ( lpData == NULL ) &&
2944       !( dwFlags & DPRECEIVE_PEEK )
2945     )
2946   {
2947     return DPERR_INVALIDPARAMS;
2948   }
2949
2950   if( dwFlags & DPRECEIVE_ALL )
2951   {
2952     lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2953
2954     if( !( dwFlags & DPRECEIVE_PEEK ) )
2955     {
2956       FIXME( "Remove from queue\n" );
2957     }
2958   }
2959   else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2960            ( dwFlags & DPRECEIVE_FROMPLAYER )
2961          )
2962   {
2963     FIXME( "Find matching message 0x%08x\n", dwFlags );
2964   }
2965   else
2966   {
2967     ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
2968   }
2969
2970   if( lpMsg == NULL )
2971   {
2972     return DPERR_NOMESSAGES;
2973   }
2974
2975   /* Copy into the provided buffer */
2976   CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
2977
2978   return DP_OK;
2979 }
2980
2981 static HRESULT WINAPI DirectPlay2AImpl_Receive
2982           ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
2983             DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2984 {
2985   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2986   return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2987                         lpData, lpdwDataSize, TRUE );
2988 }
2989
2990 static HRESULT WINAPI DirectPlay2WImpl_Receive
2991           ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
2992             DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2993 {
2994   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2995   return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2996                         lpData, lpdwDataSize, FALSE );
2997 }
2998
2999 static HRESULT WINAPI DirectPlay2AImpl_Send
3000           ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3001 {
3002   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3003   return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3004                     0, 0, NULL, NULL, TRUE );
3005 }
3006
3007 static HRESULT WINAPI DirectPlay2WImpl_Send
3008           ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3009 {
3010   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3011   return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3012                     0, 0, NULL, NULL, FALSE );
3013 }
3014
3015 static HRESULT WINAPI DP_IF_SetGroupData
3016           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3017             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3018 {
3019   lpGroupData lpGData;
3020
3021   TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3022          This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3023
3024   /* Parameter check */
3025   if( ( lpData == NULL ) &&
3026       ( dwDataSize != 0 )
3027     )
3028   {
3029     return DPERR_INVALIDPARAMS;
3030   }
3031
3032   /* Find the pointer to the data for this player */
3033   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3034   {
3035     return DPERR_INVALIDOBJECT;
3036   }
3037
3038   if( !(dwFlags & DPSET_LOCAL) )
3039   {
3040     FIXME( "Was this group created by this interface?\n" );
3041     /* FIXME: If this is a remote update need to allow it but not
3042      *        send a message.
3043      */
3044   }
3045
3046   DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3047
3048   /* FIXME: Only send a message if this group is local to the session otherwise
3049    * it will have been rejected above
3050    */
3051   if( !(dwFlags & DPSET_LOCAL) )
3052   {
3053     FIXME( "Send msg?\n" );
3054   }
3055
3056   return DP_OK;
3057 }
3058
3059 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3060           ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3061             DWORD dwDataSize, DWORD dwFlags )
3062 {
3063   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3064   return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3065 }
3066
3067 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3068           ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3069             DWORD dwDataSize, DWORD dwFlags )
3070 {
3071   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3072   return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3073 }
3074
3075 static HRESULT WINAPI DP_IF_SetGroupName
3076           ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3077             DWORD dwFlags, BOOL bAnsi )
3078 {
3079   lpGroupData lpGData;
3080
3081   TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3082          lpGroupName, dwFlags, bAnsi );
3083
3084   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3085   {
3086     return DPERR_INVALIDGROUP;
3087   }
3088
3089   DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3090
3091   /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3092   FIXME( "Message not sent and dwFlags ignored\n" );
3093
3094   return DP_OK;
3095 }
3096
3097 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3098           ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3099             DWORD dwFlags )
3100 {
3101   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3102   return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3103 }
3104
3105 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3106           ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3107             DWORD dwFlags )
3108 {
3109   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3110   return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3111 }
3112
3113 static HRESULT WINAPI DP_IF_SetPlayerData
3114           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3115             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3116 {
3117   lpPlayerList lpPList;
3118
3119   TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3120          This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3121
3122   /* Parameter check */
3123   if( ( lpData == NULL ) &&
3124       ( dwDataSize != 0 )
3125     )
3126   {
3127     return DPERR_INVALIDPARAMS;
3128   }
3129
3130   /* Find the pointer to the data for this player */
3131   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3132   {
3133     return DPERR_INVALIDPLAYER;
3134   }
3135
3136   if( !(dwFlags & DPSET_LOCAL) )
3137   {
3138     FIXME( "Was this group created by this interface?\n" );
3139     /* FIXME: If this is a remote update need to allow it but not
3140      *        send a message.
3141      */
3142   }
3143
3144   DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3145
3146   if( !(dwFlags & DPSET_LOCAL) )
3147   {
3148     FIXME( "Send msg?\n" );
3149   }
3150
3151   return DP_OK;
3152 }
3153
3154 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3155           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3156             DWORD dwDataSize, DWORD dwFlags )
3157 {
3158   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3159   return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3160                               dwFlags, TRUE );
3161 }
3162
3163 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3164           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3165             DWORD dwDataSize, DWORD dwFlags )
3166 {
3167   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3168   return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3169                               dwFlags, FALSE );
3170 }
3171
3172 static HRESULT WINAPI DP_IF_SetPlayerName
3173           ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3174             DWORD dwFlags, BOOL bAnsi )
3175 {
3176   lpPlayerList lpPList;
3177
3178   TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3179          This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3180
3181   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3182   {
3183     return DPERR_INVALIDGROUP;
3184   }
3185
3186   DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3187
3188   /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3189   FIXME( "Message not sent and dwFlags ignored\n" );
3190
3191   return DP_OK;
3192 }
3193
3194 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3195           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3196             DWORD dwFlags )
3197 {
3198   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3199   return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3200 }
3201
3202 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3203           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3204             DWORD dwFlags )
3205 {
3206   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3207   return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3208 }
3209
3210 static HRESULT WINAPI DP_SetSessionDesc
3211           ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3212             DWORD dwFlags, BOOL bInitial, BOOL bAnsi  )
3213 {
3214   DWORD            dwRequiredSize;
3215   LPDPSESSIONDESC2 lpTempSessDesc;
3216
3217   TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3218          This, lpSessDesc, dwFlags, bInitial, bAnsi );
3219
3220   if( This->dp2->connectionInitialized == NO_PROVIDER )
3221   {
3222     return DPERR_UNINITIALIZED;
3223   }
3224
3225   if( dwFlags )
3226   {
3227     return DPERR_INVALIDPARAMS;
3228   }
3229
3230   /* Only the host is allowed to update the session desc */
3231   if( !This->dp2->bHostInterface )
3232   {
3233     return DPERR_ACCESSDENIED;
3234   }
3235
3236   /* FIXME: Copy into This->dp2->lpSessionDesc */
3237   dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3238   lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3239
3240   if( lpTempSessDesc == NULL )
3241   {
3242     return DPERR_OUTOFMEMORY;
3243   }
3244
3245   /* Free the old */
3246   HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3247
3248   This->dp2->lpSessionDesc = lpTempSessDesc;
3249   if( bInitial )
3250   {
3251     /*Initializing session GUID*/
3252     CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3253   }
3254   /* Set the new */
3255   DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3256
3257   /* If this is an external invocation of the interface, we should be
3258    * letting everyone know that things have changed. Otherwise this is
3259    * just an initialization and it doesn't need to be propagated.
3260    */
3261   if( !bInitial )
3262   {
3263     FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3264   }
3265
3266   return DP_OK;
3267 }
3268
3269 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3270           ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3271 {
3272   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3273   return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3274 }
3275
3276 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3277           ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3278 {
3279   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3280   return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3281 }
3282
3283 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3284 DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3285 {
3286   DWORD dwSize = 0;
3287
3288   if( lpSessDesc == NULL )
3289   {
3290     /* Hmmm..don't need any size? */
3291     ERR( "NULL lpSessDesc\n" );
3292     return dwSize;
3293   }
3294
3295   dwSize += sizeof( *lpSessDesc );
3296
3297   if( bAnsi )
3298   {
3299     if( lpSessDesc->u1.lpszSessionNameA )
3300     {
3301       dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3302     }
3303
3304     if( lpSessDesc->u2.lpszPasswordA )
3305     {
3306       dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3307     }
3308   }
3309   else /* UNICODE */
3310   {
3311     if( lpSessDesc->u1.lpszSessionName )
3312     {
3313       dwSize += sizeof( WCHAR ) *
3314         ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3315     }
3316
3317     if( lpSessDesc->u2.lpszPassword )
3318     {
3319       dwSize += sizeof( WCHAR ) *
3320         ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3321     }
3322   }
3323
3324   return dwSize;
3325 }
3326
3327 /* Assumes that contugous buffers are already allocated. */
3328 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3329                                 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3330 {
3331   BYTE* lpStartOfFreeSpace;
3332
3333   if( lpSessionDest == NULL )
3334   {
3335     ERR( "NULL lpSessionDest\n" );
3336     return;
3337   }
3338
3339   CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3340
3341   lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3342
3343   if( bAnsi )
3344   {
3345     if( lpSessionSrc->u1.lpszSessionNameA )
3346     {
3347       lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3348                 lpSessionDest->u1.lpszSessionNameA );
3349       lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3350       lpStartOfFreeSpace +=
3351         lstrlenA( (LPSTR)lpSessionDest->u1.lpszSessionNameA ) + 1;
3352     }
3353
3354     if( lpSessionSrc->u2.lpszPasswordA )
3355     {
3356       lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3357                 lpSessionDest->u2.lpszPasswordA );
3358       lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3359       lpStartOfFreeSpace +=
3360         lstrlenA( (LPSTR)lpSessionDest->u2.lpszPasswordA ) + 1;
3361     }
3362   }
3363   else /* UNICODE */
3364   {
3365     if( lpSessionSrc->u1.lpszSessionName )
3366     {
3367       lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3368                 lpSessionDest->u1.lpszSessionName );
3369       lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3370       lpStartOfFreeSpace += sizeof(WCHAR) *
3371         ( lstrlenW( (LPWSTR)lpSessionDest->u1.lpszSessionName ) + 1 );
3372     }
3373
3374     if( lpSessionSrc->u2.lpszPassword )
3375     {
3376       lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3377                 lpSessionDest->u2.lpszPassword );
3378       lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3379       lpStartOfFreeSpace += sizeof(WCHAR) *
3380         ( lstrlenW( (LPWSTR)lpSessionDest->u2.lpszPassword ) + 1 );
3381     }
3382   }
3383 }
3384
3385
3386 static HRESULT WINAPI DP_IF_AddGroupToGroup
3387           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3388 {
3389   lpGroupData lpGParentData;
3390   lpGroupData lpGData;
3391   lpGroupList lpNewGList;
3392
3393   TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3394
3395   if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3396   {
3397     return DPERR_INVALIDGROUP;
3398   }
3399
3400   if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3401   {
3402     return DPERR_INVALIDGROUP;
3403   }
3404
3405   /* Create a player list (ie "shortcut" ) */
3406   lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3407   if( lpNewGList == NULL )
3408   {
3409     return DPERR_CANTADDPLAYER;
3410   }
3411
3412   /* Add the shortcut */
3413   lpGData->uRef++;
3414   lpNewGList->lpGData = lpGData;
3415
3416   /* Add the player to the list of players for this group */
3417   DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3418
3419   /* Send a ADDGROUPTOGROUP message */
3420   FIXME( "Not sending message\n" );
3421
3422   return DP_OK;
3423 }
3424
3425 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3426           ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3427 {
3428   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3429   return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3430 }
3431
3432 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3433           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3434 {
3435   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3436   return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3437 }
3438
3439 static HRESULT WINAPI DP_IF_CreateGroupInGroup
3440           ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3441             LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3442             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3443 {
3444   lpGroupData lpGParentData;
3445   lpGroupList lpGList;
3446   lpGroupData lpGData;
3447
3448   TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3449          This, idParentGroup, lpidGroup, lpGroupName, lpData,
3450          dwDataSize, dwFlags, bAnsi );
3451
3452   /* Verify that the specified parent is valid */
3453   if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3454                                          idParentGroup ) ) == NULL
3455     )
3456   {
3457     return DPERR_INVALIDGROUP;
3458   }
3459
3460   lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3461                             dwFlags, idParentGroup, bAnsi );
3462
3463   if( lpGData == NULL )
3464   {
3465     return DPERR_CANTADDPLAYER; /* yes player not group */
3466   }
3467
3468   /* Something else is referencing this data */
3469   lpGData->uRef++;
3470
3471   DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3472
3473   /* The list has now been inserted into the interface group list. We now
3474      need to put a "shortcut" to this group in the parent group */
3475   lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3476   if( lpGList == NULL )
3477   {
3478     FIXME( "Memory leak\n" );
3479     return DPERR_CANTADDPLAYER; /* yes player not group */
3480   }
3481
3482   lpGList->lpGData = lpGData;
3483
3484   DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3485
3486   /* Let the SP know that we've created this group */
3487   if( This->dp2->spData.lpCB->CreateGroup )
3488   {
3489     DPSP_CREATEGROUPDATA data;
3490
3491     TRACE( "Calling SP CreateGroup\n" );
3492
3493     data.idGroup           = *lpidGroup;
3494     data.dwFlags           = dwFlags;
3495     data.lpSPMessageHeader = lpMsgHdr;
3496     data.lpISP             = This->dp2->spData.lpISP;
3497
3498     (*This->dp2->spData.lpCB->CreateGroup)( &data );
3499   }
3500
3501   /* Inform all other peers of the creation of a new group. If there are
3502    * no peers keep this quiet.
3503    */
3504   if( This->dp2->lpSessionDesc &&
3505       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3506   {
3507     DPMSG_CREATEPLAYERORGROUP msg;
3508
3509     msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3510     msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3511     msg.dpId = *lpidGroup;
3512     msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3513     msg.lpData = lpData;
3514     msg.dwDataSize = dwDataSize;
3515     msg.dpnName = *lpGroupName;
3516
3517     /* FIXME: Correct to just use send effectively? */
3518     /* FIXME: Should size include data w/ message or just message "header" */
3519     /* FIXME: Check return code */
3520     DP_SendEx( (IDirectPlay2Impl*)This,
3521                DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3522                0, 0, NULL, NULL, bAnsi );
3523   }
3524
3525   return DP_OK;
3526 }
3527
3528 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3529           ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3530             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3531             DWORD dwFlags )
3532 {
3533   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3534
3535   *lpidGroup = DPID_UNKNOWN;
3536
3537   return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3538                                    lpGroupName, lpData, dwDataSize, dwFlags,
3539                                    TRUE );
3540 }
3541
3542 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3543           ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3544             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3545             DWORD dwFlags )
3546 {
3547   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3548
3549   *lpidGroup = DPID_UNKNOWN;
3550
3551   return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3552                                    lpGroupName, lpData, dwDataSize,
3553                                    dwFlags, FALSE );
3554 }
3555
3556 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
3557           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3558 {
3559   lpGroupList lpGList;
3560   lpGroupData lpGParentData;
3561
3562   TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3563
3564   /* Is the parent group valid? */
3565   if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3566   {
3567     return DPERR_INVALIDGROUP;
3568   }
3569
3570   /* Remove the group from the parent group queue */
3571   DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3572
3573   if( lpGList == NULL )
3574   {
3575     return DPERR_INVALIDGROUP;
3576   }
3577
3578   /* Decrement the ref count */
3579   lpGList->lpGData->uRef--;
3580
3581   /* Free up the list item */
3582   HeapFree( GetProcessHeap(), 0, lpGList );
3583
3584   /* Should send a DELETEGROUPFROMGROUP message */
3585   FIXME( "message not sent\n" );
3586
3587   return DP_OK;
3588 }
3589
3590 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3591           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3592 {
3593   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3594   return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3595 }
3596
3597 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3598           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3599 {
3600   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3601   return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3602 }
3603
3604 static
3605 BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3606                                     LPDWORD lpdwBufSize )
3607 {
3608   DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3609   HRESULT                  hr;
3610
3611   dpCompoundAddress.dwDataSize = sizeof( GUID );
3612   memcpy( &dpCompoundAddress.guidDataType, &DPAID_ServiceProvider,
3613           sizeof( GUID ) ) ;
3614   dpCompoundAddress.lpData = lpcSpGuid;
3615
3616   *lplpAddrBuf = NULL;
3617   *lpdwBufSize = 0;
3618
3619   hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3620                                   lpdwBufSize, TRUE );
3621
3622   if( hr != DPERR_BUFFERTOOSMALL )
3623   {
3624     ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3625     return FALSE;
3626   }
3627
3628   /* Now allocate the buffer */
3629   *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3630                             *lpdwBufSize );
3631
3632   hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3633                                   lpdwBufSize, TRUE );
3634   if( FAILED(hr) )
3635   {
3636     ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3637     return FALSE;
3638   }
3639
3640   return TRUE;
3641 }
3642
3643 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
3644           ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3645 {
3646   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3647   TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3648
3649   /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3650   if( dwFlags == 0 )
3651   {
3652     dwFlags = DPCONNECTION_DIRECTPLAY;
3653   }
3654
3655   if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3656           ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3657     )
3658   {
3659     return DPERR_INVALIDFLAGS;
3660   }
3661
3662   if( !lpEnumCallback || !*lpEnumCallback )
3663   {
3664      return DPERR_INVALIDPARAMS;
3665   }
3666
3667   /* Enumerate DirectPlay service providers */
3668   if( dwFlags & DPCONNECTION_DIRECTPLAY )
3669   {
3670     HKEY hkResult;
3671     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3672     LPCSTR guidDataSubKey  = "Guid";
3673     char subKeyName[51];
3674     DWORD dwIndex, sizeOfSubKeyName=50;
3675     FILETIME filetime;
3676
3677     /* Need to loop over the service providers in the registry */
3678     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3679                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3680     {
3681       /* Hmmm. Does this mean that there are no service providers? */
3682       ERR(": no service providers?\n");
3683       return DP_OK;
3684     }
3685
3686
3687     /* Traverse all the service providers we have available */
3688     for( dwIndex=0;
3689          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3690                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3691          ++dwIndex, sizeOfSubKeyName=51 )
3692     {
3693
3694       HKEY     hkServiceProvider;
3695       GUID     serviceProviderGUID;
3696       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
3697       char     returnBuffer[51];
3698       WCHAR    buff[51];
3699       DPNAME   dpName;
3700       BOOL     bBuildPass;
3701
3702       LPVOID                   lpAddressBuffer = NULL;
3703       DWORD                    dwAddressBufferSize = 0;
3704
3705       TRACE(" this time through: %s\n", subKeyName );
3706
3707       /* Get a handle for this particular service provider */
3708       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3709                          &hkServiceProvider ) != ERROR_SUCCESS )
3710       {
3711          ERR(": what the heck is going on?\n" );
3712          continue;
3713       }
3714
3715       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3716                             NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3717                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3718       {
3719         ERR(": missing GUID registry data members\n" );
3720         continue;
3721       }
3722
3723       /* FIXME: Check return types to ensure we're interpreting data right */
3724       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3725       CLSIDFromString( buff, &serviceProviderGUID );
3726       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3727
3728       /* Fill in the DPNAME struct for the service provider */
3729       dpName.dwSize             = sizeof( dpName );
3730       dpName.dwFlags            = 0;
3731       dpName.u1.lpszShortNameA = subKeyName;
3732       dpName.u2.lpszLongNameA  = NULL;
3733
3734       /* Create the compound address for the service provider.
3735        * NOTE: This is a gruesome architectural scar right now.  DP
3736        * uses DPL and DPL uses DP.  Nasty stuff. This may be why the
3737        * native dll just gets around this little bit by allocating an
3738        * 80 byte buffer which isn't even filled with a valid compound
3739        * address. Oh well. Creating a proper compound address is the
3740        * way to go anyways despite this method taking slightly more
3741        * heap space and realtime :) */
3742
3743       bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3744                                            &lpAddressBuffer,
3745                                            &dwAddressBufferSize );
3746       if( !bBuildPass )
3747       {
3748         ERR( "Can't build compound addr\n" );
3749         return DPERR_GENERIC;
3750       }
3751
3752       /* The enumeration will return FALSE if we are not to continue */
3753       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3754                            &dpName, DPCONNECTION_DIRECTPLAY, lpContext ) )
3755       {
3756          return DP_OK;
3757       }
3758     }
3759   }
3760
3761   /* Enumerate DirectPlayLobby service providers */
3762   if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3763   {
3764     HKEY hkResult;
3765     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3766     LPCSTR guidDataSubKey  = "Guid";
3767     char subKeyName[51];
3768     DWORD dwIndex, sizeOfSubKeyName=50;
3769     FILETIME filetime;
3770
3771     /* Need to loop over the service providers in the registry */
3772     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3773                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3774     {
3775       /* Hmmm. Does this mean that there are no service providers? */
3776       ERR(": no service providers?\n");
3777       return DP_OK;
3778     }
3779
3780
3781     /* Traverse all the lobby providers we have available */
3782     for( dwIndex=0;
3783          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3784                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3785          ++dwIndex, sizeOfSubKeyName=51 )
3786     {
3787
3788       HKEY     hkServiceProvider;
3789       GUID     serviceProviderGUID;
3790       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
3791       char     returnBuffer[51];
3792       WCHAR    buff[51];
3793       DPNAME   dpName;
3794       HRESULT  hr;
3795
3796       DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3797       LPVOID                   lpAddressBuffer = NULL;
3798       DWORD                    dwAddressBufferSize = 0;
3799
3800       TRACE(" this time through: %s\n", subKeyName );
3801
3802       /* Get a handle for this particular service provider */
3803       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3804                          &hkServiceProvider ) != ERROR_SUCCESS )
3805       {
3806          ERR(": what the heck is going on?\n" );
3807          continue;
3808       }
3809
3810       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3811                             NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3812                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3813       {
3814         ERR(": missing GUID registry data members\n" );
3815         continue;
3816       }
3817
3818       /* FIXME: Check return types to ensure we're interpreting data right */
3819       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3820       CLSIDFromString( buff, &serviceProviderGUID );
3821       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3822
3823       /* Fill in the DPNAME struct for the service provider */
3824       dpName.dwSize             = sizeof( dpName );
3825       dpName.dwFlags            = 0;
3826       dpName.u1.lpszShortNameA = subKeyName;
3827       dpName.u2.lpszLongNameA  = NULL;
3828
3829       /* Create the compound address for the service provider.
3830          NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3831                nast stuff. This may be why the native dll just gets around this little bit by
3832                allocating an 80 byte buffer which isn't even a filled with a valid compound
3833                address. Oh well. Creating a proper compound address is the way to go anyways
3834                despite this method taking slightly more heap space and realtime :) */
3835
3836       dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3837       dpCompoundAddress.dwDataSize   = sizeof( GUID );
3838       dpCompoundAddress.lpData       = &serviceProviderGUID;
3839
3840       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3841                                      &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3842       {
3843         ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3844         return hr;
3845       }
3846
3847       /* Now allocate the buffer */
3848       lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3849
3850       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3851                                      &dwAddressBufferSize, TRUE ) ) != DP_OK )
3852       {
3853         ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3854         return hr;
3855       }
3856
3857       /* The enumeration will return FALSE if we are not to continue */
3858       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3859                            &dpName, DPCONNECTION_DIRECTPLAYLOBBY, lpContext ) )
3860       {
3861          return DP_OK;
3862       }
3863     }
3864   }
3865
3866   return DP_OK;
3867 }
3868
3869 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3870           ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3871 {
3872   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3873   FIXME("(%p)->(%p,%p,%p,0x%08x): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3874   return DP_OK;
3875 }
3876
3877 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
3878           ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3879             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3880             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3881 {
3882   lpGroupList lpGList;
3883   lpGroupData lpGData;
3884
3885   FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
3886          This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3887          lpContext, dwFlags, bAnsi );
3888
3889   if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3890   {
3891     return DPERR_INVALIDGROUP;
3892   }
3893
3894   if( DPQ_IS_EMPTY( lpGData->groups ) )
3895   {
3896     return DP_OK;
3897   }
3898
3899   lpGList = DPQ_FIRST( lpGData->groups );
3900
3901   for( ;; )
3902   {
3903     /* FIXME: Should check dwFlags for match here */
3904
3905     if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3906                                     &lpGList->lpGData->name, dwFlags,
3907                                     lpContext ) )
3908     {
3909       return DP_OK; /* User requested break */
3910     }
3911
3912     if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3913     {
3914       break;
3915     }
3916
3917     lpGList = DPQ_NEXT( lpGList->groups );
3918
3919   }
3920
3921   return DP_OK;
3922 }
3923
3924 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
3925           ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3926             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3927             DWORD dwFlags )
3928 {
3929   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3930   return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3931                                   lpEnumPlayersCallback2, lpContext, dwFlags,
3932                                   TRUE );
3933 }
3934
3935 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3936           ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3937             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3938             DWORD dwFlags )
3939 {
3940   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3941   return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3942                                   lpEnumPlayersCallback2, lpContext, dwFlags,
3943                                   FALSE );
3944 }
3945
3946 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
3947           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3948 {
3949   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3950   FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3951   return DP_OK;
3952 }
3953
3954 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
3955           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3956 {
3957   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3958   FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3959   return DP_OK;
3960 }
3961
3962 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
3963     REFGUID         guidDataType,
3964     DWORD           dwDataSize,
3965     LPCVOID         lpData,
3966     LPVOID          lpContext )
3967 {
3968   /* Looking for the GUID of the provider to load */
3969   if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
3970       ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
3971     )
3972   {
3973     TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
3974            debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
3975
3976     if( dwDataSize != sizeof( GUID ) )
3977     {
3978       ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
3979     }
3980
3981     memcpy( lpContext, lpData, dwDataSize );
3982
3983     /* There shouldn't be more than 1 GUID/compound address */
3984     return FALSE;
3985   }
3986
3987   /* Still waiting for what we want */
3988   return TRUE;
3989 }
3990
3991
3992 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
3993 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
3994 {
3995   UINT i;
3996   LPCSTR spSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3997   LPCSTR lpSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3998   LPCSTR guidDataSubKey   = "Guid";
3999   LPCSTR majVerDataSubKey = "dwReserved1";
4000   LPCSTR minVerDataSubKey = "dwReserved2";
4001   LPCSTR pathSubKey       = "Path";
4002
4003   TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4004
4005   /* FIXME: Cloned code with a quick hack. */
4006   for( i=0; i<2; i++ )
4007   {
4008     HKEY hkResult;
4009     LPCSTR searchSubKey;
4010     char subKeyName[51];
4011     DWORD dwIndex, sizeOfSubKeyName=50;
4012     FILETIME filetime;
4013
4014     (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4015     *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4016
4017
4018     /* Need to loop over the service providers in the registry */
4019     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4020                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4021     {
4022       /* Hmmm. Does this mean that there are no service providers? */
4023       ERR(": no service providers?\n");
4024       return 0;
4025     }
4026
4027     /* Traverse all the service providers we have available */
4028     for( dwIndex=0;
4029          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4030                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4031          ++dwIndex, sizeOfSubKeyName=51 )
4032     {
4033
4034       HKEY     hkServiceProvider;
4035       GUID     serviceProviderGUID;
4036       DWORD    returnType, sizeOfReturnBuffer = 255;
4037       char     returnBuffer[256];
4038       WCHAR    buff[51];
4039       DWORD    dwTemp, len;
4040
4041       TRACE(" this time through: %s\n", subKeyName );
4042
4043       /* Get a handle for this particular service provider */
4044       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4045                          &hkServiceProvider ) != ERROR_SUCCESS )
4046       {
4047          ERR(": what the heck is going on?\n" );
4048          continue;
4049       }
4050
4051       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4052                             NULL, &returnType, (LPBYTE)returnBuffer,
4053                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4054       {
4055         ERR(": missing GUID registry data members\n" );
4056         continue;
4057       }
4058
4059       /* FIXME: Check return types to ensure we're interpreting data right */
4060       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4061       CLSIDFromString( buff, &serviceProviderGUID );
4062       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4063
4064       /* Determine if this is the Service Provider that the user asked for */
4065       if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4066       {
4067         continue;
4068       }
4069
4070       if( i == 0 ) /* DP SP */
4071       {
4072         len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4073         lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4074         MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4075       }
4076
4077       sizeOfReturnBuffer = 255;
4078
4079       /* Get dwReserved1 */
4080       if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4081                             NULL, &returnType, (LPBYTE)returnBuffer,
4082                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4083       {
4084          ERR(": missing dwReserved1 registry data members\n") ;
4085          continue;
4086       }
4087
4088       if( i == 0 )
4089           memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4090
4091       sizeOfReturnBuffer = 255;
4092
4093       /* Get dwReserved2 */
4094       if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4095                             NULL, &returnType, (LPBYTE)returnBuffer,
4096                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4097       {
4098          ERR(": missing dwReserved1 registry data members\n") ;
4099          continue;
4100       }
4101
4102       if( i == 0 )
4103           memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4104
4105       sizeOfReturnBuffer = 255;
4106
4107       /* Get the path for this service provider */
4108       if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4109                             NULL, NULL, (LPBYTE)returnBuffer,
4110                             &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4111       {
4112         ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4113         continue;
4114       }
4115
4116       TRACE( "Loading %s\n", returnBuffer );
4117       return LoadLibraryA( returnBuffer );
4118     }
4119   }
4120
4121   return 0;
4122 }
4123
4124 static
4125 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4126 {
4127   HRESULT hr;
4128   LPDPSP_SPINIT SPInit;
4129
4130   /* Initialize the service provider by calling SPInit */
4131   SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4132
4133   if( SPInit == NULL )
4134   {
4135     ERR( "Service provider doesn't provide SPInit interface?\n" );
4136     FreeLibrary( hServiceProvider );
4137     return DPERR_UNAVAILABLE;
4138   }
4139
4140   TRACE( "Calling SPInit (DP SP entry point)\n" );
4141
4142   hr = (*SPInit)( &This->dp2->spData );
4143
4144   if( FAILED(hr) )
4145   {
4146     ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4147     FreeLibrary( hServiceProvider );
4148     return hr;
4149   }
4150
4151   /* FIXME: Need to verify the sanity of the returned callback table
4152    *        using IsBadCodePtr */
4153   This->dp2->bSPInitialized = TRUE;
4154
4155   /* This interface is now initialized as a DP object */
4156   This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4157
4158   /* Store the handle of the module so that we can unload it later */
4159   This->dp2->hServiceProvider = hServiceProvider;
4160
4161   return hr;
4162 }
4163
4164 static
4165 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4166 {
4167   HRESULT hr;
4168   LPSP_INIT DPLSPInit;
4169
4170   /* Initialize the service provider by calling SPInit */
4171   DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4172
4173   if( DPLSPInit == NULL )
4174   {
4175     ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4176     FreeLibrary( hLobbyProvider );
4177     return DPERR_UNAVAILABLE;
4178   }
4179
4180   TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4181
4182   hr = (*DPLSPInit)( &This->dp2->dplspData );
4183
4184   if( FAILED(hr) )
4185   {
4186     ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4187     FreeLibrary( hLobbyProvider );
4188     return hr;
4189   }
4190
4191   /* FIXME: Need to verify the sanity of the returned callback table
4192    *        using IsBadCodePtr */
4193
4194   This->dp2->bDPLSPInitialized = TRUE;
4195
4196   /* This interface is now initialized as a lobby object */
4197   This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4198
4199   /* Store the handle of the module so that we can unload it later */
4200   This->dp2->hDPLobbyProvider = hLobbyProvider;
4201
4202   return hr;
4203 }
4204
4205 static HRESULT WINAPI DP_IF_InitializeConnection
4206           ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4207 {
4208   HMODULE hServiceProvider;
4209   HRESULT hr;
4210   GUID guidSP;
4211   const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4212   BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4213
4214   TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4215
4216   if( dwFlags != 0 )
4217   {
4218     return DPERR_INVALIDFLAGS;
4219   }
4220
4221   /* Find out what the requested SP is and how large this buffer is */
4222   hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4223                         dwAddrSize, &guidSP );
4224
4225   if( FAILED(hr) )
4226   {
4227     ERR( "Invalid compound address?\n" );
4228     return DPERR_UNAVAILABLE;
4229   }
4230
4231   /* Load the service provider */
4232   hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4233
4234   if( hServiceProvider == 0 )
4235   {
4236     ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4237     return DPERR_UNAVAILABLE;
4238   }
4239
4240   if( bIsDpSp )
4241   {
4242      /* Fill in what we can of the Service Provider required information.
4243       * The rest was be done in DP_LoadSP
4244       */
4245      This->dp2->spData.lpAddress = lpConnection;
4246      This->dp2->spData.dwAddressSize = dwAddrSize;
4247      This->dp2->spData.lpGuid = &guidSP;
4248
4249      hr = DP_InitializeDPSP( This, hServiceProvider );
4250   }
4251   else
4252   {
4253      This->dp2->dplspData.lpAddress = lpConnection;
4254
4255      hr = DP_InitializeDPLSP( This, hServiceProvider );
4256   }
4257
4258   if( FAILED(hr) )
4259   {
4260     return hr;
4261   }
4262
4263   return DP_OK;
4264 }
4265
4266 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4267           ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4268 {
4269   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4270
4271   /* This may not be externally invoked once either an SP or LP is initialized */
4272   if( This->dp2->connectionInitialized != NO_PROVIDER )
4273   {
4274     return DPERR_ALREADYINITIALIZED;
4275   }
4276
4277   return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4278 }
4279
4280 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4281           ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4282 {
4283   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4284
4285   /* This may not be externally invoked once either an SP or LP is initialized */
4286   if( This->dp2->connectionInitialized != NO_PROVIDER )
4287   {
4288     return DPERR_ALREADYINITIALIZED;
4289   }
4290
4291   return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4292 }
4293
4294 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4295           ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4296             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4297 {
4298   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4299   return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4300 }
4301
4302 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4303           ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4304             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4305 {
4306   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4307   return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4308 }
4309
4310 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4311           ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4312 {
4313   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4314   FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4315   return DP_OK;
4316 }
4317
4318 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4319           ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4320 {
4321   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4322   FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4323   return DP_OK;
4324 }
4325
4326 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4327           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4328 {
4329   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4330   FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4331   return DP_OK;
4332 }
4333
4334 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4335           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4336 {
4337   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4338   FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4339   return DP_OK;
4340 }
4341
4342 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4343           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4344 {
4345   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4346   FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4347   return DP_OK;
4348 }
4349
4350 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4351           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4352 {
4353   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4354   FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4355   return DP_OK;
4356 }
4357
4358 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4359           ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4360 {
4361   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4362   FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4363   return DP_OK;
4364 }
4365
4366 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4367           ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4368 {
4369   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4370   FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4371   return DP_OK;
4372 }
4373
4374 static HRESULT WINAPI DP_IF_GetGroupParent
4375           ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4376             BOOL bAnsi )
4377 {
4378   lpGroupData lpGData;
4379
4380   TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4381
4382   if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4383   {
4384     return DPERR_INVALIDGROUP;
4385   }
4386
4387   *lpidGroup = lpGData->dpid;
4388
4389   return DP_OK;
4390 }
4391
4392 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4393           ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4394 {
4395   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4396   return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4397 }
4398 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4399           ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4400 {
4401   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4402   return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4403 }
4404
4405 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4406           ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4407 {
4408   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4409   FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4410   return DP_OK;
4411 }
4412
4413 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4414           ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4415 {
4416   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4417   FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4418   return DP_OK;
4419 }
4420
4421 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4422           ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4423 {
4424   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4425   FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4426   return DP_OK;
4427 }
4428
4429 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4430           ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4431 {
4432   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4433   FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4434   return DP_OK;
4435 }
4436
4437 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4438           ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4439 {
4440   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4441   FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4442   return DP_OK;
4443 }
4444
4445 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4446           ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4447 {
4448   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4449   FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4450   return DP_OK;
4451 }
4452
4453 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4454           ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4455 {
4456   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4457   FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4458   return DP_OK;
4459 }
4460
4461 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4462           ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4463 {
4464   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4465   FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4466   return DP_OK;
4467 }
4468
4469 static HRESULT WINAPI DP_SendEx
4470           ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4471             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4472             LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4473 {
4474   lpPlayerList lpPList;
4475   lpGroupData  lpGData;
4476   BOOL         bValidDestination = FALSE;
4477
4478   FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4479          ": stub\n",
4480          This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4481          dwTimeout, lpContext, lpdwMsgID, bAnsi );
4482
4483   /* FIXME: Add parameter checking */
4484   /* FIXME: First call to this needs to acquire a message id which will be
4485    *        used for multiple sends
4486    */
4487
4488   /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4489
4490   /* Verify that the message is being sent from a valid local player. The
4491    * from player may be anonymous DPID_UNKNOWN
4492    */
4493   if( idFrom != DPID_UNKNOWN )
4494   {
4495     if( ( lpPList = DP_FindPlayer( This, idFrom ) ) == NULL )
4496     {
4497       WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4498       return DPERR_INVALIDPLAYER;
4499     }
4500   }
4501
4502   /* Verify that the message is being sent to a valid player, group or to
4503    * everyone. If it's valid, send it to those players.
4504    */
4505   if( idTo == DPID_ALLPLAYERS )
4506   {
4507     bValidDestination = TRUE;
4508
4509     /* See if SP has the ability to multicast. If so, use it */
4510     if( This->dp2->spData.lpCB->SendToGroupEx )
4511     {
4512       FIXME( "Use group sendex to group 0\n" );
4513     }
4514     else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4515     {
4516       FIXME( "Use obsolete group send to group 0\n" );
4517     }
4518     else /* No multicast, multiplicate */
4519     {
4520       /* Send to all players we know about */
4521       FIXME( "Send to all players using EnumPlayersInGroup\n" );
4522     }
4523   }
4524
4525   if( ( !bValidDestination ) &&
4526       ( DP_FindPlayer( This, idTo ) != NULL )
4527     )
4528   {
4529     bValidDestination = TRUE;
4530
4531     /* Have the service provider send this message */
4532     /* FIXME: Could optimize for local interface sends */
4533     return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4534                          dwTimeout, lpContext, lpdwMsgID );
4535   }
4536
4537   if( ( !bValidDestination ) &&
4538       ( ( lpGData = DP_FindAnyGroup( This, idTo ) ) != NULL )
4539     )
4540   {
4541     bValidDestination = TRUE;
4542
4543     /* See if SP has the ability to multicast. If so, use it */
4544     if( This->dp2->spData.lpCB->SendToGroupEx )
4545     {
4546       FIXME( "Use group sendex\n" );
4547     }
4548     else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4549     {
4550       FIXME( "Use obsolete group send to group\n" );
4551     }
4552     else /* No multicast, multiplicate */
4553     {
4554       FIXME( "Send to all players using EnumPlayersInGroup\n" );
4555     }
4556
4557 #if 0
4558     if( bExpectReply )
4559     {
4560       DWORD dwWaitReturn;
4561
4562       This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4563
4564       dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4565       if( dwWaitReturn != WAIT_OBJECT_0 )
4566       {
4567         ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4568       }
4569     }
4570 #endif
4571   }
4572
4573   if( !bValidDestination )
4574   {
4575     return DPERR_INVALIDPLAYER;
4576   }
4577   else
4578   {
4579     /* FIXME: Should return what the send returned */
4580     return DP_OK;
4581   }
4582 }
4583
4584
4585 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4586           ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4587             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4588             LPVOID lpContext, LPDWORD lpdwMsgID )
4589 {
4590   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4591   return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4592                     dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4593 }
4594
4595 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4596           ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4597             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4598             LPVOID lpContext, LPDWORD lpdwMsgID )
4599 {
4600   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4601   return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4602                     dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4603 }
4604
4605 static HRESULT WINAPI DP_SP_SendEx
4606           ( IDirectPlay2Impl* This, DWORD dwFlags,
4607             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4608             LPVOID lpContext, LPDWORD lpdwMsgID )
4609 {
4610   LPDPMSG lpMElem;
4611
4612   FIXME( ": stub\n" );
4613
4614   /* FIXME: This queuing should only be for async messages */
4615
4616   lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4617   lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4618
4619   CopyMemory( lpMElem->msg, lpData, dwDataSize );
4620
4621   /* FIXME: Need to queue based on priority */
4622   DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4623
4624   return DP_OK;
4625 }
4626
4627 static HRESULT WINAPI DP_IF_GetMessageQueue
4628           ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4629             LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4630 {
4631   HRESULT hr = DP_OK;
4632
4633   FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4634          This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4635
4636   /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4637   /* FIXME: What about sends which are not immediate? */
4638
4639   if( This->dp2->spData.lpCB->GetMessageQueue )
4640   {
4641     DPSP_GETMESSAGEQUEUEDATA data;
4642
4643     FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4644
4645     /* FIXME: None of this is documented :( */
4646
4647     data.lpISP        = This->dp2->spData.lpISP;
4648     data.dwFlags      = dwFlags;
4649     data.idFrom       = idFrom;
4650     data.idTo         = idTo;
4651     data.lpdwNumMsgs  = lpdwNumMsgs;
4652     data.lpdwNumBytes = lpdwNumBytes;
4653
4654     hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4655   }
4656   else
4657   {
4658     FIXME( "No SP for GetMessageQueue - fake some data\n" );
4659   }
4660
4661   return hr;
4662 }
4663
4664 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4665           ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4666             LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4667 {
4668   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4669   return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4670                                 lpdwNumBytes, TRUE );
4671 }
4672
4673 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4674           ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4675             LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4676 {
4677   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4678   return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4679                                 lpdwNumBytes, FALSE );
4680 }
4681
4682 static HRESULT WINAPI DP_IF_CancelMessage
4683           ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4684             DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4685 {
4686   HRESULT hr = DP_OK;
4687
4688   FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4689          This, dwMsgID, dwFlags, bAnsi );
4690
4691   if( This->dp2->spData.lpCB->Cancel )
4692   {
4693     DPSP_CANCELDATA data;
4694
4695     TRACE( "Calling SP Cancel\n" );
4696
4697     /* FIXME: Undocumented callback */
4698
4699     data.lpISP          = This->dp2->spData.lpISP;
4700     data.dwFlags        = dwFlags;
4701     data.lprglpvSPMsgID = NULL;
4702     data.cSPMsgID       = dwMsgID;
4703     data.dwMinPriority  = dwMinPriority;
4704     data.dwMaxPriority  = dwMaxPriority;
4705
4706     hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4707   }
4708   else
4709   {
4710     FIXME( "SP doesn't implement Cancel\n" );
4711   }
4712
4713   return hr;
4714 }
4715
4716 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4717           ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4718 {
4719   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4720
4721   if( dwFlags != 0 )
4722   {
4723     return DPERR_INVALIDFLAGS;
4724   }
4725
4726   if( dwMsgID == 0 )
4727   {
4728     dwFlags |= DPCANCELSEND_ALL;
4729   }
4730
4731   return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4732 }
4733
4734 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4735           ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4736 {
4737   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4738
4739   if( dwFlags != 0 )
4740   {
4741     return DPERR_INVALIDFLAGS;
4742   }
4743
4744   if( dwMsgID == 0 )
4745   {
4746     dwFlags |= DPCANCELSEND_ALL;
4747   }
4748
4749   return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4750 }
4751
4752 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4753           ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4754             DWORD dwFlags )
4755 {
4756   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4757
4758   if( dwFlags != 0 )
4759   {
4760     return DPERR_INVALIDFLAGS;
4761   }
4762
4763   return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4764                               dwMaxPriority, TRUE );
4765 }
4766
4767 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4768           ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4769             DWORD dwFlags )
4770 {
4771   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4772
4773   if( dwFlags != 0 )
4774   {
4775     return DPERR_INVALIDFLAGS;
4776   }
4777
4778   return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4779                               dwMaxPriority, FALSE );
4780 }
4781
4782 /* Note: Hack so we can reuse the old functions without compiler warnings */
4783 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4784 # define XCAST(fun)     (typeof(directPlay2WVT.fun))
4785 #else
4786 # define XCAST(fun)     (void*)
4787 #endif
4788
4789 static const IDirectPlay2Vtbl directPlay2WVT =
4790 {
4791   XCAST(QueryInterface)DP_QueryInterface,
4792   XCAST(AddRef)DP_AddRef,
4793   XCAST(Release)DP_Release,
4794
4795   DirectPlay2WImpl_AddPlayerToGroup,
4796   DirectPlay2WImpl_Close,
4797   DirectPlay2WImpl_CreateGroup,
4798   DirectPlay2WImpl_CreatePlayer,
4799   DirectPlay2WImpl_DeletePlayerFromGroup,
4800   DirectPlay2WImpl_DestroyGroup,
4801   DirectPlay2WImpl_DestroyPlayer,
4802   DirectPlay2WImpl_EnumGroupPlayers,
4803   DirectPlay2WImpl_EnumGroups,
4804   DirectPlay2WImpl_EnumPlayers,
4805   DirectPlay2WImpl_EnumSessions,
4806   DirectPlay2WImpl_GetCaps,
4807   DirectPlay2WImpl_GetGroupData,
4808   DirectPlay2WImpl_GetGroupName,
4809   DirectPlay2WImpl_GetMessageCount,
4810   DirectPlay2WImpl_GetPlayerAddress,
4811   DirectPlay2WImpl_GetPlayerCaps,
4812   DirectPlay2WImpl_GetPlayerData,
4813   DirectPlay2WImpl_GetPlayerName,
4814   DirectPlay2WImpl_GetSessionDesc,
4815   DirectPlay2WImpl_Initialize,
4816   DirectPlay2WImpl_Open,
4817   DirectPlay2WImpl_Receive,
4818   DirectPlay2WImpl_Send,
4819   DirectPlay2WImpl_SetGroupData,
4820   DirectPlay2WImpl_SetGroupName,
4821   DirectPlay2WImpl_SetPlayerData,
4822   DirectPlay2WImpl_SetPlayerName,
4823   DirectPlay2WImpl_SetSessionDesc
4824 };
4825 #undef XCAST
4826
4827 /* Note: Hack so we can reuse the old functions without compiler warnings */
4828 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4829 # define XCAST(fun)     (typeof(directPlay2AVT.fun))
4830 #else
4831 # define XCAST(fun)     (void*)
4832 #endif
4833
4834 static const IDirectPlay2Vtbl directPlay2AVT =
4835 {
4836   XCAST(QueryInterface)DP_QueryInterface,
4837   XCAST(AddRef)DP_AddRef,
4838   XCAST(Release)DP_Release,
4839
4840   DirectPlay2AImpl_AddPlayerToGroup,
4841   DirectPlay2AImpl_Close,
4842   DirectPlay2AImpl_CreateGroup,
4843   DirectPlay2AImpl_CreatePlayer,
4844   DirectPlay2AImpl_DeletePlayerFromGroup,
4845   DirectPlay2AImpl_DestroyGroup,
4846   DirectPlay2AImpl_DestroyPlayer,
4847   DirectPlay2AImpl_EnumGroupPlayers,
4848   DirectPlay2AImpl_EnumGroups,
4849   DirectPlay2AImpl_EnumPlayers,
4850   DirectPlay2AImpl_EnumSessions,
4851   DirectPlay2AImpl_GetCaps,
4852   DirectPlay2AImpl_GetGroupData,
4853   DirectPlay2AImpl_GetGroupName,
4854   DirectPlay2AImpl_GetMessageCount,
4855   DirectPlay2AImpl_GetPlayerAddress,
4856   DirectPlay2AImpl_GetPlayerCaps,
4857   DirectPlay2AImpl_GetPlayerData,
4858   DirectPlay2AImpl_GetPlayerName,
4859   DirectPlay2AImpl_GetSessionDesc,
4860   DirectPlay2AImpl_Initialize,
4861   DirectPlay2AImpl_Open,
4862   DirectPlay2AImpl_Receive,
4863   DirectPlay2AImpl_Send,
4864   DirectPlay2AImpl_SetGroupData,
4865   DirectPlay2AImpl_SetGroupName,
4866   DirectPlay2AImpl_SetPlayerData,
4867   DirectPlay2AImpl_SetPlayerName,
4868   DirectPlay2AImpl_SetSessionDesc
4869 };
4870 #undef XCAST
4871
4872
4873 /* Note: Hack so we can reuse the old functions without compiler warnings */
4874 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4875 # define XCAST(fun)     (typeof(directPlay3AVT.fun))
4876 #else
4877 # define XCAST(fun)     (void*)
4878 #endif
4879
4880 static const IDirectPlay3Vtbl directPlay3AVT =
4881 {
4882   XCAST(QueryInterface)DP_QueryInterface,
4883   XCAST(AddRef)DP_AddRef,
4884   XCAST(Release)DP_Release,
4885
4886   XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
4887   XCAST(Close)DirectPlay2AImpl_Close,
4888   XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
4889   XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
4890   XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
4891   XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
4892   XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
4893   XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
4894   XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
4895   XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
4896   XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
4897   XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
4898   XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
4899   XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
4900   XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
4901   XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
4902   XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
4903   XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
4904   XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
4905   XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
4906   XCAST(Initialize)DirectPlay2AImpl_Initialize,
4907   XCAST(Open)DirectPlay2AImpl_Open,
4908   XCAST(Receive)DirectPlay2AImpl_Receive,
4909   XCAST(Send)DirectPlay2AImpl_Send,
4910   XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
4911   XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
4912   XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
4913   XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
4914   XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
4915
4916   DirectPlay3AImpl_AddGroupToGroup,
4917   DirectPlay3AImpl_CreateGroupInGroup,
4918   DirectPlay3AImpl_DeleteGroupFromGroup,
4919   DirectPlay3AImpl_EnumConnections,
4920   DirectPlay3AImpl_EnumGroupsInGroup,
4921   DirectPlay3AImpl_GetGroupConnectionSettings,
4922   DirectPlay3AImpl_InitializeConnection,
4923   DirectPlay3AImpl_SecureOpen,
4924   DirectPlay3AImpl_SendChatMessage,
4925   DirectPlay3AImpl_SetGroupConnectionSettings,
4926   DirectPlay3AImpl_StartSession,
4927   DirectPlay3AImpl_GetGroupFlags,
4928   DirectPlay3AImpl_GetGroupParent,
4929   DirectPlay3AImpl_GetPlayerAccount,
4930   DirectPlay3AImpl_GetPlayerFlags
4931 };
4932 #undef XCAST
4933
4934 /* Note: Hack so we can reuse the old functions without compiler warnings */
4935 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4936 # define XCAST(fun)     (typeof(directPlay3WVT.fun))
4937 #else
4938 # define XCAST(fun)     (void*)
4939 #endif
4940 static const IDirectPlay3Vtbl directPlay3WVT =
4941 {
4942   XCAST(QueryInterface)DP_QueryInterface,
4943   XCAST(AddRef)DP_AddRef,
4944   XCAST(Release)DP_Release,
4945
4946   XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
4947   XCAST(Close)DirectPlay2WImpl_Close,
4948   XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
4949   XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
4950   XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
4951   XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
4952   XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
4953   XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
4954   XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
4955   XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
4956   XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
4957   XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
4958   XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
4959   XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
4960   XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
4961   XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
4962   XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
4963   XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
4964   XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
4965   XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
4966   XCAST(Initialize)DirectPlay2WImpl_Initialize,
4967   XCAST(Open)DirectPlay2WImpl_Open,
4968   XCAST(Receive)DirectPlay2WImpl_Receive,
4969   XCAST(Send)DirectPlay2WImpl_Send,
4970   XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
4971   XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
4972   XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
4973   XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
4974   XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
4975
4976   DirectPlay3WImpl_AddGroupToGroup,
4977   DirectPlay3WImpl_CreateGroupInGroup,
4978   DirectPlay3WImpl_DeleteGroupFromGroup,
4979   DirectPlay3WImpl_EnumConnections,
4980   DirectPlay3WImpl_EnumGroupsInGroup,
4981   DirectPlay3WImpl_GetGroupConnectionSettings,
4982   DirectPlay3WImpl_InitializeConnection,
4983   DirectPlay3WImpl_SecureOpen,
4984   DirectPlay3WImpl_SendChatMessage,
4985   DirectPlay3WImpl_SetGroupConnectionSettings,
4986   DirectPlay3WImpl_StartSession,
4987   DirectPlay3WImpl_GetGroupFlags,
4988   DirectPlay3WImpl_GetGroupParent,
4989   DirectPlay3WImpl_GetPlayerAccount,
4990   DirectPlay3WImpl_GetPlayerFlags
4991 };
4992 #undef XCAST
4993
4994 /* Note: Hack so we can reuse the old functions without compiler warnings */
4995 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4996 # define XCAST(fun)     (typeof(directPlay4WVT.fun))
4997 #else
4998 # define XCAST(fun)     (void*)
4999 #endif
5000 static const IDirectPlay4Vtbl directPlay4WVT =
5001 {
5002   XCAST(QueryInterface)DP_QueryInterface,
5003   XCAST(AddRef)DP_AddRef,
5004   XCAST(Release)DP_Release,
5005
5006   XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5007   XCAST(Close)DirectPlay2WImpl_Close,
5008   XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5009   XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5010   XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5011   XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5012   XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5013   XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5014   XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5015   XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5016   XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5017   XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5018   XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5019   XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5020   XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5021   XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5022   XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5023   XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5024   XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5025   XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5026   XCAST(Initialize)DirectPlay2WImpl_Initialize,
5027   XCAST(Open)DirectPlay2WImpl_Open,
5028   XCAST(Receive)DirectPlay2WImpl_Receive,
5029   XCAST(Send)DirectPlay2WImpl_Send,
5030   XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5031   XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5032   XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5033   XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5034   XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5035
5036   XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5037   XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5038   XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5039   XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5040   XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5041   XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5042   XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5043   XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5044   XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5045   XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5046   XCAST(StartSession)DirectPlay3WImpl_StartSession,
5047   XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5048   XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5049   XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5050   XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5051
5052   DirectPlay4WImpl_GetGroupOwner,
5053   DirectPlay4WImpl_SetGroupOwner,
5054   DirectPlay4WImpl_SendEx,
5055   DirectPlay4WImpl_GetMessageQueue,
5056   DirectPlay4WImpl_CancelMessage,
5057   DirectPlay4WImpl_CancelPriority
5058 };
5059 #undef XCAST
5060
5061
5062 /* Note: Hack so we can reuse the old functions without compiler warnings */
5063 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5064 # define XCAST(fun)     (typeof(directPlay4AVT.fun))
5065 #else
5066 # define XCAST(fun)     (void*)
5067 #endif
5068 static const IDirectPlay4Vtbl directPlay4AVT =
5069 {
5070   XCAST(QueryInterface)DP_QueryInterface,
5071   XCAST(AddRef)DP_AddRef,
5072   XCAST(Release)DP_Release,
5073
5074   XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5075   XCAST(Close)DirectPlay2AImpl_Close,
5076   XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5077   XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5078   XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5079   XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5080   XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5081   XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5082   XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5083   XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5084   XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5085   XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5086   XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5087   XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5088   XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5089   XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5090   XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5091   XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5092   XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5093   XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5094   XCAST(Initialize)DirectPlay2AImpl_Initialize,
5095   XCAST(Open)DirectPlay2AImpl_Open,
5096   XCAST(Receive)DirectPlay2AImpl_Receive,
5097   XCAST(Send)DirectPlay2AImpl_Send,
5098   XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5099   XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5100   XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5101   XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5102   XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5103
5104   XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5105   XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5106   XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5107   XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5108   XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5109   XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5110   XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5111   XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5112   XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5113   XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5114   XCAST(StartSession)DirectPlay3AImpl_StartSession,
5115   XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5116   XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5117   XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5118   XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5119
5120   DirectPlay4AImpl_GetGroupOwner,
5121   DirectPlay4AImpl_SetGroupOwner,
5122   DirectPlay4AImpl_SendEx,
5123   DirectPlay4AImpl_GetMessageQueue,
5124   DirectPlay4AImpl_CancelMessage,
5125   DirectPlay4AImpl_CancelPriority
5126 };
5127 #undef XCAST
5128
5129 extern
5130 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5131                             DPID idPlayer,
5132                             LPVOID* lplpData )
5133 {
5134   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5135
5136   if( lpPlayer == NULL )
5137   {
5138     return DPERR_INVALIDPLAYER;
5139   }
5140
5141   *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5142
5143   return DP_OK;
5144 }
5145
5146 extern
5147 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5148                             DPID idPlayer,
5149                             LPVOID lpData )
5150 {
5151   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5152
5153   if( lpPlayer == NULL )
5154   {
5155     return DPERR_INVALIDPLAYER;
5156   }
5157
5158   lpPlayer->lpPData->lpSPPlayerData = lpData;
5159
5160   return DP_OK;
5161 }
5162
5163 /***************************************************************************
5164  *  DirectPlayEnumerateAW
5165  *
5166  *  The pointer to the structure lpContext will be filled with the
5167  *  appropriate data for each service offered by the OS. These services are
5168  *  not necessarily available on this particular machine but are defined
5169  *  as simple service providers under the "Service Providers" registry key.
5170  *  This structure is then passed to lpEnumCallback for each of the different
5171  *  services.
5172  *
5173  *  This API is useful only for applications written using DirectX3 or
5174  *  worse. It is superseded by IDirectPlay3::EnumConnections which also
5175  *  gives information on the actual connections.
5176  *
5177  * defn of a service provider:
5178  * A dynamic-link library used by DirectPlay to communicate over a network.
5179  * The service provider contains all the network-specific code required
5180  * to send and receive messages. Online services and network operators can
5181  * supply service providers to use specialized hardware, protocols, communications
5182  * media, and network resources.
5183  *
5184  */
5185 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5186                                      LPDPENUMDPCALLBACKW lpEnumCallbackW,
5187                                      LPVOID lpContext)
5188 {
5189     HKEY   hkResult;
5190     static const WCHAR searchSubKey[] = {
5191         'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5192         'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5193         'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5194         'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5195     static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5196     static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5197     
5198     DWORD  dwIndex;
5199     FILETIME filetime;
5200
5201     char  *descriptionA = NULL;
5202     DWORD max_sizeOfDescriptionA = 0;
5203     WCHAR *descriptionW = NULL;
5204     DWORD max_sizeOfDescriptionW = 0;
5205     
5206     if (!lpEnumCallbackA && !lpEnumCallbackW)
5207     {
5208         return DPERR_INVALIDPARAMS;
5209     }
5210     
5211     /* Need to loop over the service providers in the registry */
5212     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5213                       0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5214     {
5215         /* Hmmm. Does this mean that there are no service providers? */
5216         ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5217         return DPERR_GENERIC;
5218     }
5219     
5220     /* Traverse all the service providers we have available */
5221     dwIndex = 0;
5222     while (1)
5223     {
5224         WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5225         DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5226         HKEY  hkServiceProvider;
5227         GUID  serviceProviderGUID;
5228         WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5229         DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5230         LONG  ret_value;
5231         
5232         ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5233                                   NULL, NULL, NULL, &filetime);
5234         if (ret_value == ERROR_NO_MORE_ITEMS)
5235             break;
5236         else if (ret_value != ERROR_SUCCESS)
5237         {
5238             ERR(": could not enumerate on service provider key.\n");
5239             return DPERR_EXCEPTION;
5240         }
5241         TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5242         
5243         /* Open the key for this service provider */
5244         if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5245         {
5246             ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5247             continue;
5248         }
5249         
5250         /* Get the GUID from the registry */
5251         if (RegQueryValueExW(hkServiceProvider, guidKey,
5252                              NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5253         {
5254             ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5255             continue;
5256         }
5257         if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5258         {
5259             ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5260             continue;
5261         }
5262         CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5263         
5264         /* The enumeration will return FALSE if we are not to continue.
5265          *
5266          * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5267          *       and have no relations to any of the two dwReserved1 and dwReserved2 keys.
5268          *       I think that it simply means that they are in-line with DirectX 6.0
5269          */
5270         if (lpEnumCallbackA)
5271         {
5272             DWORD sizeOfDescription = 0;
5273             
5274             /* Note that this the the A case of this function, so use the A variant to get the description string */
5275             if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5276                                  NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5277             {
5278                 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5279                 continue;
5280             }
5281             if (sizeOfDescription > max_sizeOfDescriptionA)
5282             {
5283                 HeapFree(GetProcessHeap(), 0, descriptionA);
5284                 max_sizeOfDescriptionA = sizeOfDescription;
5285                 descriptionA = HeapAlloc(GetProcessHeap(), 0, max_sizeOfDescriptionA);
5286             }
5287             descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5288             RegQueryValueExA(hkServiceProvider, "DescriptionA",
5289                              NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5290             
5291             if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5292                 goto end;
5293         }
5294         else
5295         {
5296             DWORD sizeOfDescription = 0;
5297             
5298             if (RegQueryValueExW(hkServiceProvider, descW,
5299                                  NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5300             {
5301                 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5302                 continue;
5303             }
5304             if (sizeOfDescription > max_sizeOfDescriptionW)
5305             {
5306                 HeapFree(GetProcessHeap(), 0, descriptionW);
5307                 max_sizeOfDescriptionW = sizeOfDescription;
5308                 descriptionW = HeapAlloc(GetProcessHeap(), 0, max_sizeOfDescriptionW);
5309             }
5310             descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5311             RegQueryValueExW(hkServiceProvider, descW,
5312                              NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5313
5314             if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5315                 goto end;
5316         }
5317       
5318       dwIndex++;
5319   }
5320
5321  end:
5322     HeapFree(GetProcessHeap(), 0, descriptionA);
5323     HeapFree(GetProcessHeap(), 0, descriptionW);
5324     
5325     return DP_OK;
5326 }
5327
5328 /***************************************************************************
5329  *  DirectPlayEnumerate  [DPLAYX.9]
5330  *  DirectPlayEnumerateA [DPLAYX.2]
5331  */
5332 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5333 {
5334     TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5335     
5336     return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5337 }
5338
5339 /***************************************************************************
5340  *  DirectPlayEnumerateW [DPLAYX.3]
5341  */
5342 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5343 {
5344     TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5345     
5346     return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5347 }
5348
5349 typedef struct tagCreateEnum
5350 {
5351   LPVOID  lpConn;
5352   LPCGUID lpGuid;
5353 } CreateEnumData, *lpCreateEnumData;
5354
5355 /* Find and copy the matching connection for the SP guid */
5356 static BOOL CALLBACK cbDPCreateEnumConnections(
5357     LPCGUID     lpguidSP,
5358     LPVOID      lpConnection,
5359     DWORD       dwConnectionSize,
5360     LPCDPNAME   lpName,
5361     DWORD       dwFlags,
5362     LPVOID      lpContext)
5363 {
5364   lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5365
5366   if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5367   {
5368     TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5369
5370     lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5371                                 dwConnectionSize );
5372     CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5373
5374     /* Found the record that we were looking for */
5375     return FALSE;
5376   }
5377
5378   /* Haven't found what were looking for yet */
5379   return TRUE;
5380 }
5381
5382
5383 /***************************************************************************
5384  *  DirectPlayCreate [DPLAYX.1]
5385  *
5386  */
5387 HRESULT WINAPI DirectPlayCreate
5388 ( LPGUID lpGUID, LPDIRECTPLAY2 *lplpDP, IUnknown *pUnk)
5389 {
5390   HRESULT hr;
5391   LPDIRECTPLAY3A lpDP3A;
5392   CreateEnumData cbData;
5393
5394   TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5395
5396   if( pUnk != NULL )
5397   {
5398     return CLASS_E_NOAGGREGATION;
5399   }
5400
5401   /* Create an IDirectPlay object. We don't support that so we'll cheat and
5402      give them an IDirectPlay2A object and hope that doesn't cause problems */
5403   if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5404   {
5405     return DPERR_UNAVAILABLE;
5406   }
5407
5408   if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5409   {
5410     /* The GUID_NULL means don't bind a service provider. Just return the
5411        interface as is */
5412     return DP_OK;
5413   }
5414
5415   /* Bind the desired service provider since lpGUID is non NULL */
5416   TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5417
5418   /* We're going to use a DP3 interface */
5419   hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5420                                     (LPVOID*)&lpDP3A );
5421   if( FAILED(hr) )
5422   {
5423     ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5424     return hr;
5425   }
5426
5427   cbData.lpConn = NULL;
5428   cbData.lpGuid = lpGUID;
5429
5430   /* We were given a service provider, find info about it... */
5431   hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5432                                      &cbData, DPCONNECTION_DIRECTPLAY );
5433   if( ( FAILED(hr) ) ||
5434       ( cbData.lpConn == NULL )
5435     )
5436   {
5437     ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5438     IDirectPlayX_Release( lpDP3A );
5439     return DPERR_UNAVAILABLE;
5440   }
5441
5442   /* Initialize the service provider */
5443   hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5444   if( FAILED(hr) )
5445   {
5446     ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5447     HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5448     IDirectPlayX_Release( lpDP3A );
5449     return hr;
5450   }
5451
5452   /* Release our version of the interface now that we're done with it */
5453   IDirectPlayX_Release( lpDP3A );
5454   HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5455
5456   return DP_OK;
5457 }