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