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