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