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