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