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