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