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