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