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