localspl: Added Slovenian translation.
[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 lpGParentData;
3400   lpGroupData lpGData;
3401   lpGroupList lpNewGList;
3402
3403   TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3404
3405   if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3406   {
3407     return DPERR_INVALIDGROUP;
3408   }
3409
3410   if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3411   {
3412     return DPERR_INVALIDGROUP;
3413   }
3414
3415   /* Create a player list (ie "shortcut" ) */
3416   lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3417   if( lpNewGList == NULL )
3418   {
3419     return DPERR_CANTADDPLAYER;
3420   }
3421
3422   /* Add the shortcut */
3423   lpGData->uRef++;
3424   lpNewGList->lpGData = lpGData;
3425
3426   /* Add the player to the list of players for this group */
3427   DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3428
3429   /* Send a ADDGROUPTOGROUP message */
3430   FIXME( "Not sending message\n" );
3431
3432   return DP_OK;
3433 }
3434
3435 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3436           ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3437 {
3438   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3439   return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3440 }
3441
3442 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3443           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3444 {
3445   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3446   return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3447 }
3448
3449 static HRESULT WINAPI DP_IF_CreateGroupInGroup
3450           ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3451             LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3452             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3453 {
3454   lpGroupData lpGParentData;
3455   lpGroupList lpGList;
3456   lpGroupData lpGData;
3457
3458   TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3459          This, idParentGroup, lpidGroup, lpGroupName, lpData,
3460          dwDataSize, dwFlags, bAnsi );
3461
3462   /* Verify that the specified parent is valid */
3463   if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3464                                          idParentGroup ) ) == NULL
3465     )
3466   {
3467     return DPERR_INVALIDGROUP;
3468   }
3469
3470   lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3471                             dwFlags, idParentGroup, bAnsi );
3472
3473   if( lpGData == NULL )
3474   {
3475     return DPERR_CANTADDPLAYER; /* yes player not group */
3476   }
3477
3478   /* Something else is referencing this data */
3479   lpGData->uRef++;
3480
3481   DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3482
3483   /* The list has now been inserted into the interface group list. We now
3484      need to put a "shortcut" to this group in the parent group */
3485   lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3486   if( lpGList == NULL )
3487   {
3488     FIXME( "Memory leak\n" );
3489     return DPERR_CANTADDPLAYER; /* yes player not group */
3490   }
3491
3492   lpGList->lpGData = lpGData;
3493
3494   DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3495
3496   /* Let the SP know that we've created this group */
3497   if( This->dp2->spData.lpCB->CreateGroup )
3498   {
3499     DPSP_CREATEGROUPDATA data;
3500
3501     TRACE( "Calling SP CreateGroup\n" );
3502
3503     data.idGroup           = *lpidGroup;
3504     data.dwFlags           = dwFlags;
3505     data.lpSPMessageHeader = lpMsgHdr;
3506     data.lpISP             = This->dp2->spData.lpISP;
3507
3508     (*This->dp2->spData.lpCB->CreateGroup)( &data );
3509   }
3510
3511   /* Inform all other peers of the creation of a new group. If there are
3512    * no peers keep this quiet.
3513    */
3514   if( This->dp2->lpSessionDesc &&
3515       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3516   {
3517     DPMSG_CREATEPLAYERORGROUP msg;
3518
3519     msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3520     msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3521     msg.dpId = *lpidGroup;
3522     msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3523     msg.lpData = lpData;
3524     msg.dwDataSize = dwDataSize;
3525     msg.dpnName = *lpGroupName;
3526
3527     /* FIXME: Correct to just use send effectively? */
3528     /* FIXME: Should size include data w/ message or just message "header" */
3529     /* FIXME: Check return code */
3530     DP_SendEx( (IDirectPlay2Impl*)This,
3531                DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3532                0, 0, NULL, NULL, bAnsi );
3533   }
3534
3535   return DP_OK;
3536 }
3537
3538 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3539           ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3540             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3541             DWORD dwFlags )
3542 {
3543   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3544
3545   *lpidGroup = DPID_UNKNOWN;
3546
3547   return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3548                                    lpGroupName, lpData, dwDataSize, dwFlags,
3549                                    TRUE );
3550 }
3551
3552 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3553           ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3554             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3555             DWORD dwFlags )
3556 {
3557   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3558
3559   *lpidGroup = DPID_UNKNOWN;
3560
3561   return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3562                                    lpGroupName, lpData, dwDataSize,
3563                                    dwFlags, FALSE );
3564 }
3565
3566 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
3567           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3568 {
3569   lpGroupList lpGList;
3570   lpGroupData lpGParentData;
3571
3572   TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3573
3574   /* Is the parent group valid? */
3575   if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3576   {
3577     return DPERR_INVALIDGROUP;
3578   }
3579
3580   /* Remove the group from the parent group queue */
3581   DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3582
3583   if( lpGList == NULL )
3584   {
3585     return DPERR_INVALIDGROUP;
3586   }
3587
3588   /* Decrement the ref count */
3589   lpGList->lpGData->uRef--;
3590
3591   /* Free up the list item */
3592   HeapFree( GetProcessHeap(), 0, lpGList );
3593
3594   /* Should send a DELETEGROUPFROMGROUP message */
3595   FIXME( "message not sent\n" );
3596
3597   return DP_OK;
3598 }
3599
3600 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3601           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3602 {
3603   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3604   return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3605 }
3606
3607 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3608           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3609 {
3610   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3611   return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3612 }
3613
3614 static
3615 BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3616                                     LPDWORD lpdwBufSize )
3617 {
3618   DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3619   HRESULT                  hr;
3620
3621   dpCompoundAddress.dwDataSize = sizeof( GUID );
3622   dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3623   dpCompoundAddress.lpData = lpcSpGuid;
3624
3625   *lplpAddrBuf = NULL;
3626   *lpdwBufSize = 0;
3627
3628   hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3629                                   lpdwBufSize, TRUE );
3630
3631   if( hr != DPERR_BUFFERTOOSMALL )
3632   {
3633     ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3634     return FALSE;
3635   }
3636
3637   /* Now allocate the buffer */
3638   *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3639                             *lpdwBufSize );
3640
3641   hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3642                                   lpdwBufSize, TRUE );
3643   if( FAILED(hr) )
3644   {
3645     ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3646     return FALSE;
3647   }
3648
3649   return TRUE;
3650 }
3651
3652 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
3653           ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3654 {
3655   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3656   TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3657
3658   /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3659   if( dwFlags == 0 )
3660   {
3661     dwFlags = DPCONNECTION_DIRECTPLAY;
3662   }
3663
3664   if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3665           ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3666     )
3667   {
3668     return DPERR_INVALIDFLAGS;
3669   }
3670
3671   if( !lpEnumCallback )
3672   {
3673      return DPERR_INVALIDPARAMS;
3674   }
3675
3676   /* Enumerate DirectPlay service providers */
3677   if( dwFlags & DPCONNECTION_DIRECTPLAY )
3678   {
3679     HKEY hkResult;
3680     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3681     LPCSTR guidDataSubKey  = "Guid";
3682     char subKeyName[51];
3683     DWORD dwIndex, sizeOfSubKeyName=50;
3684     FILETIME filetime;
3685
3686     /* Need to loop over the service providers in the registry */
3687     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3688                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3689     {
3690       /* Hmmm. Does this mean that there are no service providers? */
3691       ERR(": no service providers?\n");
3692       return DP_OK;
3693     }
3694
3695
3696     /* Traverse all the service providers we have available */
3697     for( dwIndex=0;
3698          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3699                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3700          ++dwIndex, sizeOfSubKeyName=51 )
3701     {
3702
3703       HKEY     hkServiceProvider;
3704       GUID     serviceProviderGUID;
3705       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
3706       char     returnBuffer[51];
3707       WCHAR    buff[51];
3708       DPNAME   dpName;
3709       BOOL     bBuildPass;
3710
3711       LPVOID                   lpAddressBuffer = NULL;
3712       DWORD                    dwAddressBufferSize = 0;
3713
3714       TRACE(" this time through: %s\n", subKeyName );
3715
3716       /* Get a handle for this particular service provider */
3717       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3718                          &hkServiceProvider ) != ERROR_SUCCESS )
3719       {
3720          ERR(": what the heck is going on?\n" );
3721          continue;
3722       }
3723
3724       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3725                             NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3726                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3727       {
3728         ERR(": missing GUID registry data members\n" );
3729         RegCloseKey(hkServiceProvider);
3730         continue;
3731       }
3732       RegCloseKey(hkServiceProvider);
3733
3734       /* FIXME: Check return types to ensure we're interpreting data right */
3735       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3736       CLSIDFromString( buff, &serviceProviderGUID );
3737       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3738
3739       /* Fill in the DPNAME struct for the service provider */
3740       dpName.dwSize             = sizeof( dpName );
3741       dpName.dwFlags            = 0;
3742       dpName.u1.lpszShortNameA = subKeyName;
3743       dpName.u2.lpszLongNameA  = NULL;
3744
3745       /* Create the compound address for the service provider.
3746        * NOTE: This is a gruesome architectural scar right now.  DP
3747        * uses DPL and DPL uses DP.  Nasty stuff. This may be why the
3748        * native dll just gets around this little bit by allocating an
3749        * 80 byte buffer which isn't even filled with a valid compound
3750        * address. Oh well. Creating a proper compound address is the
3751        * way to go anyways despite this method taking slightly more
3752        * heap space and realtime :) */
3753
3754       bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3755                                            &lpAddressBuffer,
3756                                            &dwAddressBufferSize );
3757       if( !bBuildPass )
3758       {
3759         ERR( "Can't build compound addr\n" );
3760         return DPERR_GENERIC;
3761       }
3762
3763       /* The enumeration will return FALSE if we are not to continue */
3764       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3765                            &dpName, DPCONNECTION_DIRECTPLAY, lpContext ) )
3766       {
3767          return DP_OK;
3768       }
3769     }
3770   }
3771
3772   /* Enumerate DirectPlayLobby service providers */
3773   if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3774   {
3775     HKEY hkResult;
3776     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3777     LPCSTR guidDataSubKey  = "Guid";
3778     char subKeyName[51];
3779     DWORD dwIndex, sizeOfSubKeyName=50;
3780     FILETIME filetime;
3781
3782     /* Need to loop over the service providers in the registry */
3783     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3784                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3785     {
3786       /* Hmmm. Does this mean that there are no service providers? */
3787       ERR(": no service providers?\n");
3788       return DP_OK;
3789     }
3790
3791
3792     /* Traverse all the lobby providers we have available */
3793     for( dwIndex=0;
3794          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3795                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3796          ++dwIndex, sizeOfSubKeyName=51 )
3797     {
3798
3799       HKEY     hkServiceProvider;
3800       GUID     serviceProviderGUID;
3801       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
3802       char     returnBuffer[51];
3803       WCHAR    buff[51];
3804       DPNAME   dpName;
3805       HRESULT  hr;
3806
3807       DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3808       LPVOID                   lpAddressBuffer = NULL;
3809       DWORD                    dwAddressBufferSize = 0;
3810
3811       TRACE(" this time through: %s\n", subKeyName );
3812
3813       /* Get a handle for this particular service provider */
3814       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3815                          &hkServiceProvider ) != ERROR_SUCCESS )
3816       {
3817          ERR(": what the heck is going on?\n" );
3818          continue;
3819       }
3820
3821       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3822                             NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3823                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3824       {
3825         ERR(": missing GUID registry data members\n" );
3826         RegCloseKey(hkServiceProvider);
3827         continue;
3828       }
3829       RegCloseKey(hkServiceProvider);
3830
3831       /* FIXME: Check return types to ensure we're interpreting data right */
3832       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3833       CLSIDFromString( buff, &serviceProviderGUID );
3834       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3835
3836       /* Fill in the DPNAME struct for the service provider */
3837       dpName.dwSize             = sizeof( dpName );
3838       dpName.dwFlags            = 0;
3839       dpName.u1.lpszShortNameA = subKeyName;
3840       dpName.u2.lpszLongNameA  = NULL;
3841
3842       /* Create the compound address for the service provider.
3843          NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3844                nast stuff. This may be why the native dll just gets around this little bit by
3845                allocating an 80 byte buffer which isn't even a filled with a valid compound
3846                address. Oh well. Creating a proper compound address is the way to go anyways
3847                despite this method taking slightly more heap space and realtime :) */
3848
3849       dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3850       dpCompoundAddress.dwDataSize   = sizeof( GUID );
3851       dpCompoundAddress.lpData       = &serviceProviderGUID;
3852
3853       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3854                                      &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3855       {
3856         ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3857         return hr;
3858       }
3859
3860       /* Now allocate the buffer */
3861       lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3862
3863       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3864                                      &dwAddressBufferSize, TRUE ) ) != DP_OK )
3865       {
3866         ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3867         HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3868         return hr;
3869       }
3870
3871       /* The enumeration will return FALSE if we are not to continue */
3872       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3873                            &dpName, DPCONNECTION_DIRECTPLAYLOBBY, lpContext ) )
3874       {
3875          HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3876          return DP_OK;
3877       }
3878       HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3879     }
3880   }
3881
3882   return DP_OK;
3883 }
3884
3885 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3886           ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3887 {
3888   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3889   FIXME("(%p)->(%p,%p,%p,0x%08x): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3890   return DP_OK;
3891 }
3892
3893 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
3894           ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3895             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3896             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3897 {
3898   lpGroupList lpGList;
3899   lpGroupData lpGData;
3900
3901   FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
3902          This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3903          lpContext, dwFlags, bAnsi );
3904
3905   if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3906   {
3907     return DPERR_INVALIDGROUP;
3908   }
3909
3910   if( DPQ_IS_EMPTY( lpGData->groups ) )
3911   {
3912     return DP_OK;
3913   }
3914
3915   lpGList = DPQ_FIRST( lpGData->groups );
3916
3917   for( ;; )
3918   {
3919     /* FIXME: Should check dwFlags for match here */
3920
3921     if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3922                                     &lpGList->lpGData->name, dwFlags,
3923                                     lpContext ) )
3924     {
3925       return DP_OK; /* User requested break */
3926     }
3927
3928     if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3929     {
3930       break;
3931     }
3932
3933     lpGList = DPQ_NEXT( lpGList->groups );
3934
3935   }
3936
3937   return DP_OK;
3938 }
3939
3940 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
3941           ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3942             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3943             DWORD dwFlags )
3944 {
3945   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3946   return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3947                                   lpEnumPlayersCallback2, lpContext, dwFlags,
3948                                   TRUE );
3949 }
3950
3951 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3952           ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3953             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3954             DWORD dwFlags )
3955 {
3956   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3957   return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3958                                   lpEnumPlayersCallback2, lpContext, dwFlags,
3959                                   FALSE );
3960 }
3961
3962 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
3963           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3964 {
3965   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3966   FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3967   return DP_OK;
3968 }
3969
3970 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
3971           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3972 {
3973   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3974   FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3975   return DP_OK;
3976 }
3977
3978 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
3979     REFGUID         guidDataType,
3980     DWORD           dwDataSize,
3981     LPCVOID         lpData,
3982     LPVOID          lpContext )
3983 {
3984   /* Looking for the GUID of the provider to load */
3985   if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
3986       ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
3987     )
3988   {
3989     TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
3990            debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
3991
3992     if( dwDataSize != sizeof( GUID ) )
3993     {
3994       ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
3995     }
3996
3997     memcpy( lpContext, lpData, dwDataSize );
3998
3999     /* There shouldn't be more than 1 GUID/compound address */
4000     return FALSE;
4001   }
4002
4003   /* Still waiting for what we want */
4004   return TRUE;
4005 }
4006
4007
4008 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4009 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4010 {
4011   UINT i;
4012   LPCSTR spSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4013   LPCSTR lpSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4014   LPCSTR guidDataSubKey   = "Guid";
4015   LPCSTR majVerDataSubKey = "dwReserved1";
4016   LPCSTR minVerDataSubKey = "dwReserved2";
4017   LPCSTR pathSubKey       = "Path";
4018
4019   TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4020
4021   /* FIXME: Cloned code with a quick hack. */
4022   for( i=0; i<2; i++ )
4023   {
4024     HKEY hkResult;
4025     LPCSTR searchSubKey;
4026     char subKeyName[51];
4027     DWORD dwIndex, sizeOfSubKeyName=50;
4028     FILETIME filetime;
4029
4030     (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4031     *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4032
4033
4034     /* Need to loop over the service providers in the registry */
4035     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4036                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4037     {
4038       /* Hmmm. Does this mean that there are no service providers? */
4039       ERR(": no service providers?\n");
4040       return 0;
4041     }
4042
4043     /* Traverse all the service providers we have available */
4044     for( dwIndex=0;
4045          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4046                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4047          ++dwIndex, sizeOfSubKeyName=51 )
4048     {
4049
4050       HKEY     hkServiceProvider;
4051       GUID     serviceProviderGUID;
4052       DWORD    returnType, sizeOfReturnBuffer = 255;
4053       char     returnBuffer[256];
4054       WCHAR    buff[51];
4055       DWORD    dwTemp, len;
4056
4057       TRACE(" this time through: %s\n", subKeyName );
4058
4059       /* Get a handle for this particular service provider */
4060       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4061                          &hkServiceProvider ) != ERROR_SUCCESS )
4062       {
4063          ERR(": what the heck is going on?\n" );
4064          continue;
4065       }
4066
4067       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4068                             NULL, &returnType, (LPBYTE)returnBuffer,
4069                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4070       {
4071         ERR(": missing GUID registry data members\n" );
4072         continue;
4073       }
4074
4075       /* FIXME: Check return types to ensure we're interpreting data right */
4076       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4077       CLSIDFromString( buff, &serviceProviderGUID );
4078       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4079
4080       /* Determine if this is the Service Provider that the user asked for */
4081       if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4082       {
4083         continue;
4084       }
4085
4086       if( i == 0 ) /* DP SP */
4087       {
4088         len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4089         lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4090         MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4091       }
4092
4093       sizeOfReturnBuffer = 255;
4094
4095       /* Get dwReserved1 */
4096       if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4097                             NULL, &returnType, (LPBYTE)returnBuffer,
4098                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4099       {
4100          ERR(": missing dwReserved1 registry data members\n") ;
4101          continue;
4102       }
4103
4104       if( i == 0 )
4105           memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4106
4107       sizeOfReturnBuffer = 255;
4108
4109       /* Get dwReserved2 */
4110       if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4111                             NULL, &returnType, (LPBYTE)returnBuffer,
4112                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4113       {
4114          ERR(": missing dwReserved1 registry data members\n") ;
4115          continue;
4116       }
4117
4118       if( i == 0 )
4119           memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4120
4121       sizeOfReturnBuffer = 255;
4122
4123       /* Get the path for this service provider */
4124       if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4125                             NULL, NULL, (LPBYTE)returnBuffer,
4126                             &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4127       {
4128         ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4129         continue;
4130       }
4131
4132       TRACE( "Loading %s\n", returnBuffer );
4133       return LoadLibraryA( returnBuffer );
4134     }
4135   }
4136
4137   return 0;
4138 }
4139
4140 static
4141 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4142 {
4143   HRESULT hr;
4144   LPDPSP_SPINIT SPInit;
4145
4146   /* Initialize the service provider by calling SPInit */
4147   SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4148
4149   if( SPInit == NULL )
4150   {
4151     ERR( "Service provider doesn't provide SPInit interface?\n" );
4152     FreeLibrary( hServiceProvider );
4153     return DPERR_UNAVAILABLE;
4154   }
4155
4156   TRACE( "Calling SPInit (DP SP entry point)\n" );
4157
4158   hr = (*SPInit)( &This->dp2->spData );
4159
4160   if( FAILED(hr) )
4161   {
4162     ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4163     FreeLibrary( hServiceProvider );
4164     return hr;
4165   }
4166
4167   /* FIXME: Need to verify the sanity of the returned callback table
4168    *        using IsBadCodePtr */
4169   This->dp2->bSPInitialized = TRUE;
4170
4171   /* This interface is now initialized as a DP object */
4172   This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4173
4174   /* Store the handle of the module so that we can unload it later */
4175   This->dp2->hServiceProvider = hServiceProvider;
4176
4177   return hr;
4178 }
4179
4180 static
4181 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4182 {
4183   HRESULT hr;
4184   LPSP_INIT DPLSPInit;
4185
4186   /* Initialize the service provider by calling SPInit */
4187   DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4188
4189   if( DPLSPInit == NULL )
4190   {
4191     ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4192     FreeLibrary( hLobbyProvider );
4193     return DPERR_UNAVAILABLE;
4194   }
4195
4196   TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4197
4198   hr = (*DPLSPInit)( &This->dp2->dplspData );
4199
4200   if( FAILED(hr) )
4201   {
4202     ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4203     FreeLibrary( hLobbyProvider );
4204     return hr;
4205   }
4206
4207   /* FIXME: Need to verify the sanity of the returned callback table
4208    *        using IsBadCodePtr */
4209
4210   This->dp2->bDPLSPInitialized = TRUE;
4211
4212   /* This interface is now initialized as a lobby object */
4213   This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4214
4215   /* Store the handle of the module so that we can unload it later */
4216   This->dp2->hDPLobbyProvider = hLobbyProvider;
4217
4218   return hr;
4219 }
4220
4221 static HRESULT WINAPI DP_IF_InitializeConnection
4222           ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4223 {
4224   HMODULE hServiceProvider;
4225   HRESULT hr;
4226   GUID guidSP;
4227   const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4228   BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4229
4230   TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4231
4232   if( dwFlags != 0 )
4233   {
4234     return DPERR_INVALIDFLAGS;
4235   }
4236
4237   /* Find out what the requested SP is and how large this buffer is */
4238   hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4239                         dwAddrSize, &guidSP );
4240
4241   if( FAILED(hr) )
4242   {
4243     ERR( "Invalid compound address?\n" );
4244     return DPERR_UNAVAILABLE;
4245   }
4246
4247   /* Load the service provider */
4248   hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4249
4250   if( hServiceProvider == 0 )
4251   {
4252     ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4253     return DPERR_UNAVAILABLE;
4254   }
4255
4256   if( bIsDpSp )
4257   {
4258      /* Fill in what we can of the Service Provider required information.
4259       * The rest was be done in DP_LoadSP
4260       */
4261      This->dp2->spData.lpAddress = lpConnection;
4262      This->dp2->spData.dwAddressSize = dwAddrSize;
4263      This->dp2->spData.lpGuid = &guidSP;
4264
4265      hr = DP_InitializeDPSP( This, hServiceProvider );
4266   }
4267   else
4268   {
4269      This->dp2->dplspData.lpAddress = lpConnection;
4270
4271      hr = DP_InitializeDPLSP( This, hServiceProvider );
4272   }
4273
4274   if( FAILED(hr) )
4275   {
4276     return hr;
4277   }
4278
4279   return DP_OK;
4280 }
4281
4282 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4283           ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4284 {
4285   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4286
4287   /* This may not be externally invoked once either an SP or LP is initialized */
4288   if( This->dp2->connectionInitialized != NO_PROVIDER )
4289   {
4290     return DPERR_ALREADYINITIALIZED;
4291   }
4292
4293   return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4294 }
4295
4296 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4297           ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4298 {
4299   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4300
4301   /* This may not be externally invoked once either an SP or LP is initialized */
4302   if( This->dp2->connectionInitialized != NO_PROVIDER )
4303   {
4304     return DPERR_ALREADYINITIALIZED;
4305   }
4306
4307   return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4308 }
4309
4310 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4311           ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4312             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4313 {
4314   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4315   return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4316 }
4317
4318 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4319           ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4320             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4321 {
4322   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4323   return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4324 }
4325
4326 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4327           ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4328 {
4329   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4330   FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4331   return DP_OK;
4332 }
4333
4334 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4335           ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4336 {
4337   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4338   FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4339   return DP_OK;
4340 }
4341
4342 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4343           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4344 {
4345   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4346   FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4347   return DP_OK;
4348 }
4349
4350 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4351           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4352 {
4353   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4354   FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4355   return DP_OK;
4356 }
4357
4358 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4359           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4360 {
4361   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4362   FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4363   return DP_OK;
4364 }
4365
4366 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4367           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4368 {
4369   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4370   FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4371   return DP_OK;
4372 }
4373
4374 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4375           ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4376 {
4377   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4378   FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4379   return DP_OK;
4380 }
4381
4382 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4383           ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4384 {
4385   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4386   FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4387   return DP_OK;
4388 }
4389
4390 static HRESULT WINAPI DP_IF_GetGroupParent
4391           ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4392             BOOL bAnsi )
4393 {
4394   lpGroupData lpGData;
4395
4396   TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4397
4398   if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4399   {
4400     return DPERR_INVALIDGROUP;
4401   }
4402
4403   *lpidGroup = lpGData->dpid;
4404
4405   return DP_OK;
4406 }
4407
4408 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4409           ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4410 {
4411   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4412   return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4413 }
4414 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4415           ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4416 {
4417   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4418   return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4419 }
4420
4421 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4422           ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4423 {
4424   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4425   FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4426   return DP_OK;
4427 }
4428
4429 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4430           ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4431 {
4432   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4433   FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4434   return DP_OK;
4435 }
4436
4437 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4438           ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4439 {
4440   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4441   FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4442   return DP_OK;
4443 }
4444
4445 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4446           ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4447 {
4448   IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4449   FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4450   return DP_OK;
4451 }
4452
4453 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4454           ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4455 {
4456   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4457   FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4458   return DP_OK;
4459 }
4460
4461 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4462           ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4463 {
4464   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4465   FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4466   return DP_OK;
4467 }
4468
4469 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4470           ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4471 {
4472   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4473   FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4474   return DP_OK;
4475 }
4476
4477 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4478           ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4479 {
4480   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4481   FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4482   return DP_OK;
4483 }
4484
4485 static HRESULT WINAPI DP_SendEx
4486           ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4487             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4488             LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4489 {
4490   lpPlayerList lpPList;
4491   lpGroupData  lpGData;
4492   BOOL         bValidDestination = FALSE;
4493
4494   FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4495          ": stub\n",
4496          This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4497          dwTimeout, lpContext, lpdwMsgID, bAnsi );
4498
4499   /* FIXME: Add parameter checking */
4500   /* FIXME: First call to this needs to acquire a message id which will be
4501    *        used for multiple sends
4502    */
4503
4504   /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4505
4506   /* Verify that the message is being sent from a valid local player. The
4507    * from player may be anonymous DPID_UNKNOWN
4508    */
4509   if( idFrom != DPID_UNKNOWN )
4510   {
4511     if( ( lpPList = DP_FindPlayer( This, idFrom ) ) == NULL )
4512     {
4513       WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4514       return DPERR_INVALIDPLAYER;
4515     }
4516   }
4517
4518   /* Verify that the message is being sent to a valid player, group or to
4519    * everyone. If it's valid, send it to those players.
4520    */
4521   if( idTo == DPID_ALLPLAYERS )
4522   {
4523     bValidDestination = TRUE;
4524
4525     /* See if SP has the ability to multicast. If so, use it */
4526     if( This->dp2->spData.lpCB->SendToGroupEx )
4527     {
4528       FIXME( "Use group sendex to group 0\n" );
4529     }
4530     else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4531     {
4532       FIXME( "Use obsolete group send to group 0\n" );
4533     }
4534     else /* No multicast, multiplicate */
4535     {
4536       /* Send to all players we know about */
4537       FIXME( "Send to all players using EnumPlayersInGroup\n" );
4538     }
4539   }
4540
4541   if( ( !bValidDestination ) &&
4542       ( DP_FindPlayer( This, idTo ) != NULL )
4543     )
4544   {
4545     bValidDestination = TRUE;
4546
4547     /* Have the service provider send this message */
4548     /* FIXME: Could optimize for local interface sends */
4549     return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4550                          dwTimeout, lpContext, lpdwMsgID );
4551   }
4552
4553   if( ( !bValidDestination ) &&
4554       ( ( lpGData = DP_FindAnyGroup( This, idTo ) ) != NULL )
4555     )
4556   {
4557     bValidDestination = TRUE;
4558
4559     /* See if SP has the ability to multicast. If so, use it */
4560     if( This->dp2->spData.lpCB->SendToGroupEx )
4561     {
4562       FIXME( "Use group sendex\n" );
4563     }
4564     else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4565     {
4566       FIXME( "Use obsolete group send to group\n" );
4567     }
4568     else /* No multicast, multiplicate */
4569     {
4570       FIXME( "Send to all players using EnumPlayersInGroup\n" );
4571     }
4572
4573 #if 0
4574     if( bExpectReply )
4575     {
4576       DWORD dwWaitReturn;
4577
4578       This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4579
4580       dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4581       if( dwWaitReturn != WAIT_OBJECT_0 )
4582       {
4583         ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4584       }
4585     }
4586 #endif
4587   }
4588
4589   if( !bValidDestination )
4590   {
4591     return DPERR_INVALIDPLAYER;
4592   }
4593   else
4594   {
4595     /* FIXME: Should return what the send returned */
4596     return DP_OK;
4597   }
4598 }
4599
4600
4601 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4602           ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4603             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4604             LPVOID lpContext, LPDWORD lpdwMsgID )
4605 {
4606   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4607   return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4608                     dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4609 }
4610
4611 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4612           ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4613             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4614             LPVOID lpContext, LPDWORD lpdwMsgID )
4615 {
4616   IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4617   return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4618                     dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4619 }
4620
4621 static HRESULT WINAPI DP_SP_SendEx
4622           ( IDirectPlay2Impl* This, DWORD dwFlags,
4623             LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4624             LPVOID lpContext, LPDWORD lpdwMsgID )
4625 {
4626   LPDPMSG lpMElem;
4627
4628   FIXME( ": stub\n" );
4629
4630   /* FIXME: This queuing should only be for async messages */
4631
4632   lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4633   lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4634
4635   CopyMemory( lpMElem->msg, lpData, dwDataSize );
4636
4637   /* FIXME: Need to queue based on priority */
4638   DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4639
4640   return DP_OK;
4641 }
4642
4643 static HRESULT WINAPI DP_IF_GetMessageQueue
4644           ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4645             LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4646 {
4647   HRESULT hr = DP_OK;
4648
4649   FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4650          This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4651
4652   /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4653   /* FIXME: What about sends which are not immediate? */
4654
4655   if( This->dp2->spData.lpCB->GetMessageQueue )
4656   {
4657     DPSP_GETMESSAGEQUEUEDATA data;
4658
4659     FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4660
4661     /* FIXME: None of this is documented :( */
4662
4663     data.lpISP        = This->dp2->spData.lpISP;
4664     data.dwFlags      = dwFlags;
4665     data.idFrom       = idFrom;
4666     data.idTo         = idTo;
4667     data.lpdwNumMsgs  = lpdwNumMsgs;
4668     data.lpdwNumBytes = lpdwNumBytes;
4669
4670     hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4671   }
4672   else
4673   {
4674     FIXME( "No SP for GetMessageQueue - fake some data\n" );
4675   }
4676
4677   return hr;
4678 }
4679
4680 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4681           ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4682             LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4683 {
4684   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4685   return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4686                                 lpdwNumBytes, TRUE );
4687 }
4688
4689 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4690           ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4691             LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4692 {
4693   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4694   return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4695                                 lpdwNumBytes, FALSE );
4696 }
4697
4698 static HRESULT WINAPI DP_IF_CancelMessage
4699           ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4700             DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4701 {
4702   HRESULT hr = DP_OK;
4703
4704   FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4705          This, dwMsgID, dwFlags, bAnsi );
4706
4707   if( This->dp2->spData.lpCB->Cancel )
4708   {
4709     DPSP_CANCELDATA data;
4710
4711     TRACE( "Calling SP Cancel\n" );
4712
4713     /* FIXME: Undocumented callback */
4714
4715     data.lpISP          = This->dp2->spData.lpISP;
4716     data.dwFlags        = dwFlags;
4717     data.lprglpvSPMsgID = NULL;
4718     data.cSPMsgID       = dwMsgID;
4719     data.dwMinPriority  = dwMinPriority;
4720     data.dwMaxPriority  = dwMaxPriority;
4721
4722     hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4723   }
4724   else
4725   {
4726     FIXME( "SP doesn't implement Cancel\n" );
4727   }
4728
4729   return hr;
4730 }
4731
4732 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4733           ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4734 {
4735   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4736
4737   if( dwFlags != 0 )
4738   {
4739     return DPERR_INVALIDFLAGS;
4740   }
4741
4742   if( dwMsgID == 0 )
4743   {
4744     dwFlags |= DPCANCELSEND_ALL;
4745   }
4746
4747   return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4748 }
4749
4750 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4751           ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4752 {
4753   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4754
4755   if( dwFlags != 0 )
4756   {
4757     return DPERR_INVALIDFLAGS;
4758   }
4759
4760   if( dwMsgID == 0 )
4761   {
4762     dwFlags |= DPCANCELSEND_ALL;
4763   }
4764
4765   return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4766 }
4767
4768 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4769           ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4770             DWORD dwFlags )
4771 {
4772   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4773
4774   if( dwFlags != 0 )
4775   {
4776     return DPERR_INVALIDFLAGS;
4777   }
4778
4779   return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4780                               dwMaxPriority, TRUE );
4781 }
4782
4783 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4784           ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4785             DWORD dwFlags )
4786 {
4787   IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4788
4789   if( dwFlags != 0 )
4790   {
4791     return DPERR_INVALIDFLAGS;
4792   }
4793
4794   return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4795                               dwMaxPriority, FALSE );
4796 }
4797
4798 /* Note: Hack so we can reuse the old functions without compiler warnings */
4799 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4800 # define XCAST(fun)     (typeof(directPlay2WVT.fun))
4801 #else
4802 # define XCAST(fun)     (void*)
4803 #endif
4804
4805 static const IDirectPlay2Vtbl directPlay2WVT =
4806 {
4807   XCAST(QueryInterface)DP_QueryInterface,
4808   XCAST(AddRef)DP_AddRef,
4809   XCAST(Release)DP_Release,
4810
4811   DirectPlay2WImpl_AddPlayerToGroup,
4812   DirectPlay2WImpl_Close,
4813   DirectPlay2WImpl_CreateGroup,
4814   DirectPlay2WImpl_CreatePlayer,
4815   DirectPlay2WImpl_DeletePlayerFromGroup,
4816   DirectPlay2WImpl_DestroyGroup,
4817   DirectPlay2WImpl_DestroyPlayer,
4818   DirectPlay2WImpl_EnumGroupPlayers,
4819   DirectPlay2WImpl_EnumGroups,
4820   DirectPlay2WImpl_EnumPlayers,
4821   DirectPlay2WImpl_EnumSessions,
4822   DirectPlay2WImpl_GetCaps,
4823   DirectPlay2WImpl_GetGroupData,
4824   DirectPlay2WImpl_GetGroupName,
4825   DirectPlay2WImpl_GetMessageCount,
4826   DirectPlay2WImpl_GetPlayerAddress,
4827   DirectPlay2WImpl_GetPlayerCaps,
4828   DirectPlay2WImpl_GetPlayerData,
4829   DirectPlay2WImpl_GetPlayerName,
4830   DirectPlay2WImpl_GetSessionDesc,
4831   DirectPlay2WImpl_Initialize,
4832   DirectPlay2WImpl_Open,
4833   DirectPlay2WImpl_Receive,
4834   DirectPlay2WImpl_Send,
4835   DirectPlay2WImpl_SetGroupData,
4836   DirectPlay2WImpl_SetGroupName,
4837   DirectPlay2WImpl_SetPlayerData,
4838   DirectPlay2WImpl_SetPlayerName,
4839   DirectPlay2WImpl_SetSessionDesc
4840 };
4841 #undef XCAST
4842
4843 /* Note: Hack so we can reuse the old functions without compiler warnings */
4844 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4845 # define XCAST(fun)     (typeof(directPlay2AVT.fun))
4846 #else
4847 # define XCAST(fun)     (void*)
4848 #endif
4849
4850 static const IDirectPlay2Vtbl directPlay2AVT =
4851 {
4852   XCAST(QueryInterface)DP_QueryInterface,
4853   XCAST(AddRef)DP_AddRef,
4854   XCAST(Release)DP_Release,
4855
4856   DirectPlay2AImpl_AddPlayerToGroup,
4857   DirectPlay2AImpl_Close,
4858   DirectPlay2AImpl_CreateGroup,
4859   DirectPlay2AImpl_CreatePlayer,
4860   DirectPlay2AImpl_DeletePlayerFromGroup,
4861   DirectPlay2AImpl_DestroyGroup,
4862   DirectPlay2AImpl_DestroyPlayer,
4863   DirectPlay2AImpl_EnumGroupPlayers,
4864   DirectPlay2AImpl_EnumGroups,
4865   DirectPlay2AImpl_EnumPlayers,
4866   DirectPlay2AImpl_EnumSessions,
4867   DirectPlay2AImpl_GetCaps,
4868   DirectPlay2AImpl_GetGroupData,
4869   DirectPlay2AImpl_GetGroupName,
4870   DirectPlay2AImpl_GetMessageCount,
4871   DirectPlay2AImpl_GetPlayerAddress,
4872   DirectPlay2AImpl_GetPlayerCaps,
4873   DirectPlay2AImpl_GetPlayerData,
4874   DirectPlay2AImpl_GetPlayerName,
4875   DirectPlay2AImpl_GetSessionDesc,
4876   DirectPlay2AImpl_Initialize,
4877   DirectPlay2AImpl_Open,
4878   DirectPlay2AImpl_Receive,
4879   DirectPlay2AImpl_Send,
4880   DirectPlay2AImpl_SetGroupData,
4881   DirectPlay2AImpl_SetGroupName,
4882   DirectPlay2AImpl_SetPlayerData,
4883   DirectPlay2AImpl_SetPlayerName,
4884   DirectPlay2AImpl_SetSessionDesc
4885 };
4886 #undef XCAST
4887
4888
4889 /* Note: Hack so we can reuse the old functions without compiler warnings */
4890 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4891 # define XCAST(fun)     (typeof(directPlay3AVT.fun))
4892 #else
4893 # define XCAST(fun)     (void*)
4894 #endif
4895
4896 static const IDirectPlay3Vtbl directPlay3AVT =
4897 {
4898   XCAST(QueryInterface)DP_QueryInterface,
4899   XCAST(AddRef)DP_AddRef,
4900   XCAST(Release)DP_Release,
4901
4902   XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
4903   XCAST(Close)DirectPlay2AImpl_Close,
4904   XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
4905   XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
4906   XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
4907   XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
4908   XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
4909   XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
4910   XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
4911   XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
4912   XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
4913   XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
4914   XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
4915   XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
4916   XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
4917   XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
4918   XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
4919   XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
4920   XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
4921   XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
4922   XCAST(Initialize)DirectPlay2AImpl_Initialize,
4923   XCAST(Open)DirectPlay2AImpl_Open,
4924   XCAST(Receive)DirectPlay2AImpl_Receive,
4925   XCAST(Send)DirectPlay2AImpl_Send,
4926   XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
4927   XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
4928   XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
4929   XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
4930   XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
4931
4932   DirectPlay3AImpl_AddGroupToGroup,
4933   DirectPlay3AImpl_CreateGroupInGroup,
4934   DirectPlay3AImpl_DeleteGroupFromGroup,
4935   DirectPlay3AImpl_EnumConnections,
4936   DirectPlay3AImpl_EnumGroupsInGroup,
4937   DirectPlay3AImpl_GetGroupConnectionSettings,
4938   DirectPlay3AImpl_InitializeConnection,
4939   DirectPlay3AImpl_SecureOpen,
4940   DirectPlay3AImpl_SendChatMessage,
4941   DirectPlay3AImpl_SetGroupConnectionSettings,
4942   DirectPlay3AImpl_StartSession,
4943   DirectPlay3AImpl_GetGroupFlags,
4944   DirectPlay3AImpl_GetGroupParent,
4945   DirectPlay3AImpl_GetPlayerAccount,
4946   DirectPlay3AImpl_GetPlayerFlags
4947 };
4948 #undef XCAST
4949
4950 /* Note: Hack so we can reuse the old functions without compiler warnings */
4951 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4952 # define XCAST(fun)     (typeof(directPlay3WVT.fun))
4953 #else
4954 # define XCAST(fun)     (void*)
4955 #endif
4956 static const IDirectPlay3Vtbl directPlay3WVT =
4957 {
4958   XCAST(QueryInterface)DP_QueryInterface,
4959   XCAST(AddRef)DP_AddRef,
4960   XCAST(Release)DP_Release,
4961
4962   XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
4963   XCAST(Close)DirectPlay2WImpl_Close,
4964   XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
4965   XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
4966   XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
4967   XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
4968   XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
4969   XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
4970   XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
4971   XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
4972   XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
4973   XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
4974   XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
4975   XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
4976   XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
4977   XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
4978   XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
4979   XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
4980   XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
4981   XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
4982   XCAST(Initialize)DirectPlay2WImpl_Initialize,
4983   XCAST(Open)DirectPlay2WImpl_Open,
4984   XCAST(Receive)DirectPlay2WImpl_Receive,
4985   XCAST(Send)DirectPlay2WImpl_Send,
4986   XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
4987   XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
4988   XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
4989   XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
4990   XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
4991
4992   DirectPlay3WImpl_AddGroupToGroup,
4993   DirectPlay3WImpl_CreateGroupInGroup,
4994   DirectPlay3WImpl_DeleteGroupFromGroup,
4995   DirectPlay3WImpl_EnumConnections,
4996   DirectPlay3WImpl_EnumGroupsInGroup,
4997   DirectPlay3WImpl_GetGroupConnectionSettings,
4998   DirectPlay3WImpl_InitializeConnection,
4999   DirectPlay3WImpl_SecureOpen,
5000   DirectPlay3WImpl_SendChatMessage,
5001   DirectPlay3WImpl_SetGroupConnectionSettings,
5002   DirectPlay3WImpl_StartSession,
5003   DirectPlay3WImpl_GetGroupFlags,
5004   DirectPlay3WImpl_GetGroupParent,
5005   DirectPlay3WImpl_GetPlayerAccount,
5006   DirectPlay3WImpl_GetPlayerFlags
5007 };
5008 #undef XCAST
5009
5010 /* Note: Hack so we can reuse the old functions without compiler warnings */
5011 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5012 # define XCAST(fun)     (typeof(directPlay4WVT.fun))
5013 #else
5014 # define XCAST(fun)     (void*)
5015 #endif
5016 static const IDirectPlay4Vtbl directPlay4WVT =
5017 {
5018   XCAST(QueryInterface)DP_QueryInterface,
5019   XCAST(AddRef)DP_AddRef,
5020   XCAST(Release)DP_Release,
5021
5022   XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5023   XCAST(Close)DirectPlay2WImpl_Close,
5024   XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5025   XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5026   XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5027   XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5028   XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5029   XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5030   XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5031   XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5032   XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5033   XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5034   XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5035   XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5036   XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5037   XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5038   XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5039   XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5040   XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5041   XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5042   XCAST(Initialize)DirectPlay2WImpl_Initialize,
5043   XCAST(Open)DirectPlay2WImpl_Open,
5044   XCAST(Receive)DirectPlay2WImpl_Receive,
5045   XCAST(Send)DirectPlay2WImpl_Send,
5046   XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5047   XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5048   XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5049   XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5050   XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5051
5052   XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5053   XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5054   XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5055   XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5056   XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5057   XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5058   XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5059   XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5060   XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5061   XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5062   XCAST(StartSession)DirectPlay3WImpl_StartSession,
5063   XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5064   XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5065   XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5066   XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5067
5068   DirectPlay4WImpl_GetGroupOwner,
5069   DirectPlay4WImpl_SetGroupOwner,
5070   DirectPlay4WImpl_SendEx,
5071   DirectPlay4WImpl_GetMessageQueue,
5072   DirectPlay4WImpl_CancelMessage,
5073   DirectPlay4WImpl_CancelPriority
5074 };
5075 #undef XCAST
5076
5077
5078 /* Note: Hack so we can reuse the old functions without compiler warnings */
5079 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5080 # define XCAST(fun)     (typeof(directPlay4AVT.fun))
5081 #else
5082 # define XCAST(fun)     (void*)
5083 #endif
5084 static const IDirectPlay4Vtbl directPlay4AVT =
5085 {
5086   XCAST(QueryInterface)DP_QueryInterface,
5087   XCAST(AddRef)DP_AddRef,
5088   XCAST(Release)DP_Release,
5089
5090   XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5091   XCAST(Close)DirectPlay2AImpl_Close,
5092   XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5093   XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5094   XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5095   XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5096   XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5097   XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5098   XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5099   XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5100   XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5101   XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5102   XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5103   XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5104   XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5105   XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5106   XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5107   XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5108   XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5109   XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5110   XCAST(Initialize)DirectPlay2AImpl_Initialize,
5111   XCAST(Open)DirectPlay2AImpl_Open,
5112   XCAST(Receive)DirectPlay2AImpl_Receive,
5113   XCAST(Send)DirectPlay2AImpl_Send,
5114   XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5115   XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5116   XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5117   XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5118   XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5119
5120   XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5121   XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5122   XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5123   XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5124   XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5125   XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5126   XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5127   XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5128   XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5129   XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5130   XCAST(StartSession)DirectPlay3AImpl_StartSession,
5131   XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5132   XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5133   XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5134   XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5135
5136   DirectPlay4AImpl_GetGroupOwner,
5137   DirectPlay4AImpl_SetGroupOwner,
5138   DirectPlay4AImpl_SendEx,
5139   DirectPlay4AImpl_GetMessageQueue,
5140   DirectPlay4AImpl_CancelMessage,
5141   DirectPlay4AImpl_CancelPriority
5142 };
5143 #undef XCAST
5144
5145 extern
5146 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5147                             DPID idPlayer,
5148                             LPVOID* lplpData )
5149 {
5150   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5151
5152   if( lpPlayer == NULL )
5153   {
5154     return DPERR_INVALIDPLAYER;
5155   }
5156
5157   *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5158
5159   return DP_OK;
5160 }
5161
5162 extern
5163 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5164                             DPID idPlayer,
5165                             LPVOID lpData )
5166 {
5167   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5168
5169   if( lpPlayer == NULL )
5170   {
5171     return DPERR_INVALIDPLAYER;
5172   }
5173
5174   lpPlayer->lpPData->lpSPPlayerData = lpData;
5175
5176   return DP_OK;
5177 }
5178
5179 /***************************************************************************
5180  *  DirectPlayEnumerateAW
5181  *
5182  *  The pointer to the structure lpContext will be filled with the
5183  *  appropriate data for each service offered by the OS. These services are
5184  *  not necessarily available on this particular machine but are defined
5185  *  as simple service providers under the "Service Providers" registry key.
5186  *  This structure is then passed to lpEnumCallback for each of the different
5187  *  services.
5188  *
5189  *  This API is useful only for applications written using DirectX3 or
5190  *  worse. It is superseded by IDirectPlay3::EnumConnections which also
5191  *  gives information on the actual connections.
5192  *
5193  * defn of a service provider:
5194  * A dynamic-link library used by DirectPlay to communicate over a network.
5195  * The service provider contains all the network-specific code required
5196  * to send and receive messages. Online services and network operators can
5197  * supply service providers to use specialized hardware, protocols, communications
5198  * media, and network resources.
5199  *
5200  */
5201 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5202                                      LPDPENUMDPCALLBACKW lpEnumCallbackW,
5203                                      LPVOID lpContext)
5204 {
5205     HKEY   hkResult;
5206     static const WCHAR searchSubKey[] = {
5207         'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5208         'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5209         'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5210         'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5211     static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5212     static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5213     
5214     DWORD  dwIndex;
5215     FILETIME filetime;
5216
5217     char  *descriptionA = NULL;
5218     DWORD max_sizeOfDescriptionA = 0;
5219     WCHAR *descriptionW = NULL;
5220     DWORD max_sizeOfDescriptionW = 0;
5221     
5222     if (!lpEnumCallbackA && !lpEnumCallbackW)
5223     {
5224         return DPERR_INVALIDPARAMS;
5225     }
5226     
5227     /* Need to loop over the service providers in the registry */
5228     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5229                       0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5230     {
5231         /* Hmmm. Does this mean that there are no service providers? */
5232         ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5233         return DPERR_GENERIC;
5234     }
5235     
5236     /* Traverse all the service providers we have available */
5237     dwIndex = 0;
5238     while (1)
5239     {
5240         WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5241         DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5242         HKEY  hkServiceProvider;
5243         GUID  serviceProviderGUID;
5244         WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5245         DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5246         LONG  ret_value;
5247         
5248         ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5249                                   NULL, NULL, NULL, &filetime);
5250         if (ret_value == ERROR_NO_MORE_ITEMS)
5251             break;
5252         else if (ret_value != ERROR_SUCCESS)
5253         {
5254             ERR(": could not enumerate on service provider key.\n");
5255             return DPERR_EXCEPTION;
5256         }
5257         TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5258         
5259         /* Open the key for this service provider */
5260         if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5261         {
5262             ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5263             continue;
5264         }
5265         
5266         /* Get the GUID from the registry */
5267         if (RegQueryValueExW(hkServiceProvider, guidKey,
5268                              NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5269         {
5270             ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5271             continue;
5272         }
5273         if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5274         {
5275             ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5276             continue;
5277         }
5278         CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5279         
5280         /* The enumeration will return FALSE if we are not to continue.
5281          *
5282          * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5283          *       and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5284          *       I think that it simply means that they are in-line with DirectX 6.0
5285          */
5286         if (lpEnumCallbackA)
5287         {
5288             DWORD sizeOfDescription = 0;
5289             
5290             /* Note that this is the A case of this function, so use the A variant to get the description string */
5291             if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5292                                  NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5293             {
5294                 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5295                 continue;
5296             }
5297             if (sizeOfDescription > max_sizeOfDescriptionA)
5298             {
5299                 HeapFree(GetProcessHeap(), 0, descriptionA);
5300                 max_sizeOfDescriptionA = sizeOfDescription;
5301             }
5302             descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5303             RegQueryValueExA(hkServiceProvider, "DescriptionA",
5304                              NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5305             
5306             if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5307                 goto end;
5308         }
5309         else
5310         {
5311             DWORD sizeOfDescription = 0;
5312             
5313             if (RegQueryValueExW(hkServiceProvider, descW,
5314                                  NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5315             {
5316                 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5317                 continue;
5318             }
5319             if (sizeOfDescription > max_sizeOfDescriptionW)
5320             {
5321                 HeapFree(GetProcessHeap(), 0, descriptionW);
5322                 max_sizeOfDescriptionW = sizeOfDescription;
5323             }
5324             descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5325             RegQueryValueExW(hkServiceProvider, descW,
5326                              NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5327
5328             if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5329                 goto end;
5330         }
5331       
5332       dwIndex++;
5333   }
5334
5335  end:
5336     HeapFree(GetProcessHeap(), 0, descriptionA);
5337     HeapFree(GetProcessHeap(), 0, descriptionW);
5338     
5339     return DP_OK;
5340 }
5341
5342 /***************************************************************************
5343  *  DirectPlayEnumerate  [DPLAYX.9]
5344  *  DirectPlayEnumerateA [DPLAYX.2]
5345  */
5346 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5347 {
5348     TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5349     
5350     return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5351 }
5352
5353 /***************************************************************************
5354  *  DirectPlayEnumerateW [DPLAYX.3]
5355  */
5356 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5357 {
5358     TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5359     
5360     return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5361 }
5362
5363 typedef struct tagCreateEnum
5364 {
5365   LPVOID  lpConn;
5366   LPCGUID lpGuid;
5367 } CreateEnumData, *lpCreateEnumData;
5368
5369 /* Find and copy the matching connection for the SP guid */
5370 static BOOL CALLBACK cbDPCreateEnumConnections(
5371     LPCGUID     lpguidSP,
5372     LPVOID      lpConnection,
5373     DWORD       dwConnectionSize,
5374     LPCDPNAME   lpName,
5375     DWORD       dwFlags,
5376     LPVOID      lpContext)
5377 {
5378   lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5379
5380   if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5381   {
5382     TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5383
5384     lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5385                                 dwConnectionSize );
5386     CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5387
5388     /* Found the record that we were looking for */
5389     return FALSE;
5390   }
5391
5392   /* Haven't found what were looking for yet */
5393   return TRUE;
5394 }
5395
5396
5397 /***************************************************************************
5398  *  DirectPlayCreate [DPLAYX.1]
5399  *
5400  */
5401 HRESULT WINAPI DirectPlayCreate
5402 ( LPGUID lpGUID, LPDIRECTPLAY2 *lplpDP, IUnknown *pUnk)
5403 {
5404   HRESULT hr;
5405   LPDIRECTPLAY3A lpDP3A;
5406   CreateEnumData cbData;
5407
5408   TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5409
5410   if( pUnk != NULL )
5411   {
5412     return CLASS_E_NOAGGREGATION;
5413   }
5414
5415   /* Create an IDirectPlay object. We don't support that so we'll cheat and
5416      give them an IDirectPlay2A object and hope that doesn't cause problems */
5417   if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5418   {
5419     return DPERR_UNAVAILABLE;
5420   }
5421
5422   if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5423   {
5424     /* The GUID_NULL means don't bind a service provider. Just return the
5425        interface as is */
5426     return DP_OK;
5427   }
5428
5429   /* Bind the desired service provider since lpGUID is non NULL */
5430   TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5431
5432   /* We're going to use a DP3 interface */
5433   hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5434                                     (LPVOID*)&lpDP3A );
5435   if( FAILED(hr) )
5436   {
5437     ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5438     return hr;
5439   }
5440
5441   cbData.lpConn = NULL;
5442   cbData.lpGuid = lpGUID;
5443
5444   /* We were given a service provider, find info about it... */
5445   hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5446                                      &cbData, DPCONNECTION_DIRECTPLAY );
5447   if( ( FAILED(hr) ) ||
5448       ( cbData.lpConn == NULL )
5449     )
5450   {
5451     ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5452     IDirectPlayX_Release( lpDP3A );
5453     return DPERR_UNAVAILABLE;
5454   }
5455
5456   /* Initialize the service provider */
5457   hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5458   if( FAILED(hr) )
5459   {
5460     ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5461     HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5462     IDirectPlayX_Release( lpDP3A );
5463     return hr;
5464   }
5465
5466   /* Release our version of the interface now that we're done with it */
5467   IDirectPlayX_Release( lpDP3A );
5468   HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5469
5470   return DP_OK;
5471 }