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