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