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