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