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