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