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