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