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