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